elementvalidator.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 180 行
SCALA
180 行
/* __ *\** ________ ___ / / ___ Scala API **** / __/ __// _ | / / / _ | (c) 2002-2006, LAMP/EPFL **** __\ \/ /__/ __ |/ /__/ __ | **** /____/\___/_/ |_/____/_/ | | **** |/ **\* */// $Id: ElementValidator.scala 12479 2007-08-06 17:14:30Z emir $package scala.xml.dtd;import ContentModel.ElemName ;import scala.util.automata._ ;/** validate children and/or attributes of an element * exceptions are created but not thrown. */class ElementValidator() extends Function1[Node,Boolean] { var exc: List[ValidationException] = Nil; protected var contentModel: ContentModel = _; protected var dfa: DetWordAutom[ElemName] = _; protected var adecls: List[AttrDecl] = _; /** set content model, enabling element validation */ def setContentModel(cm:ContentModel) = { contentModel = cm; cm match { case ELEMENTS( r ) => val nfa = ContentModel.Translator.automatonFrom(r, 1); dfa = new SubsetConstruction(nfa).determinize; case _ => dfa = null; } } def getContentModel = contentModel; /** set meta data, enabling attribute validation */ def setMetaData(adecls: List[AttrDecl]) = this.adecls = adecls; def getIterator(nodes: Seq[Node], skipPCDATA: Boolean): Iterator[ElemName] = nodes.toList .filter { x => x match { case y:SpecialNode => y match { case a:Atom[_] if (a.data.isInstanceOf[String] && a.data.asInstanceOf[String].trim.length == 0 ) => false; // always skip all-whitespace nodes case _ => !skipPCDATA } case _ => x.namespace eq null }} . map { x => ElemName(x.label) } . elements; /** check attributes, return true if md corresponds to attribute declarations in adecls. */ def check(md: MetaData): Boolean = { //Console.println("checking md = "+md); //Console.println("adecls = "+adecls); //@todo other exceptions import MakeValidationException._; val len: Int = exc.length; var j = 0; var ok = new scala.collection.mutable.BitSet(adecls.length); def find(Key:String): AttrDecl = { var attr: AttrDecl = null; val jt = adecls.elements; while(j < adecls.length) { jt.next match { case a @ AttrDecl(Key, _, _) => attr = a; ok += j; j = adecls.length; case _ => j = j + 1; } } attr } val it = md.elements; while(it.hasNext) { val attr = it.next; //Console.println("attr:"+attr); j = 0; find(attr.key) match { case null => //Console.println("exc"); exc = fromUndefinedAttribute( attr.key ) :: exc; case AttrDecl(_, tpe, DEFAULT(true, fixedValue)) if(attr.value != fixedValue) => exc = fromFixedAttribute( attr.key, fixedValue, attr.value.toString) :: exc; case s => //Console.println("s: "+s); } } //Console.println("so far:"+(exc.length == len)); //val missing = ok.toSet( false ); FIXME: it doesn't seem to be used anywhere j = 0; var kt = adecls.elements; while(kt.hasNext) { kt.next match { case AttrDecl(key, tpe, REQUIRED) if !ok(j) => exc = fromMissingAttribute( key, tpe ) :: exc; j = j + 1; case _ => j = j + 1; } } //Console.println("finish:"+(exc.length == len)); (exc.length == len) //- true if no new exception } /** check children, return true if conform to content model * @pre contentModel != null */ def check(nodes: Seq[Node]): Boolean = contentModel match { case ANY => true ; case EMPTY => !getIterator(nodes, false).hasNext case PCDATA => !getIterator(nodes, true).hasNext; case MIXED(ContentModel.Alt(branches @ _*)) => //@todo val j = exc.length; def find(Key: String): Boolean = { var res = false; val jt = branches.elements; while(jt.hasNext && !res) jt.next match { // !!! check for match translation problem case ContentModel.Letter(ElemName(Key)) => res = true; case _ => } res } var it = getIterator(nodes, true); while(it.hasNext) { var label = it.next.name; if(!find(label)) { exc = MakeValidationException.fromUndefinedElement(label) :: exc; } } (exc.length == j) //- true if no new exception case _:ELEMENTS => var q = 0; val it = getIterator(nodes, false); //Console.println("it empty from the start? "+(!it.hasNext)); while( it.hasNext ) { val e = it.next; dfa.delta(q).get(e) match { case Some(p) => q = p; case _ => throw ValidationException("element "+e+" not allowed here") } //Console.println("q now " + q); } dfa.isFinal(q) //- true if arrived in final state } /** applies various validations - accumulates error messages in exc * @todo: fail on first error, ignore other errors (rearranging conditions) */ def apply(n: Node): Boolean = { //- ? check children var res = (null == contentModel) || check( n.child ); //- ? check attributes res = ((null == adecls) || check( n.attributes )) && res; res } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?