diff options
author | buraq <buraq@epfl.ch> | 2004-10-21 15:32:02 +0000 |
---|---|---|
committer | buraq <buraq@epfl.ch> | 2004-10-21 15:32:02 +0000 |
commit | 4e7330335e6241a5c5260c1b1d1edadc20f93d52 (patch) | |
tree | e94d984312272bb2e1a3c59e8db293b5a64fe82e /sources | |
parent | f609e1d7cdf49bec32eebda0662d1f1d3d19c401 (diff) | |
download | scala-4e7330335e6241a5c5260c1b1d1edadc20f93d52.tar.gz scala-4e7330335e6241a5c5260c1b1d1edadc20f93d52.tar.bz2 scala-4e7330335e6241a5c5260c1b1d1edadc20f93d52.zip |
changes to XML lib
Diffstat (limited to 'sources')
-rw-r--r-- | sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml | 2 | ||||
-rw-r--r-- | sources/scala/xml/AttributeSeq.scala | 34 | ||||
-rw-r--r-- | sources/scala/xml/BindingFactoryAdapter.scala | 20 | ||||
-rw-r--r-- | sources/scala/xml/Node.scala | 8 | ||||
-rw-r--r-- | sources/scala/xml/NodeBuffer.scala | 9 | ||||
-rw-r--r-- | sources/scala/xml/NodeFactory.scala | 67 | ||||
-rw-r--r-- | sources/scala/xml/UName.scala | 4 | ||||
-rw-r--r-- | sources/scala/xml/Utility.scala | 5 | ||||
-rw-r--r-- | sources/scala/xml/nobinding/NoBindingFactoryAdapter.scala | 14 |
9 files changed, 153 insertions, 10 deletions
diff --git a/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml b/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml index 8d62a371d2..57a7d5ce3e 100644 --- a/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml +++ b/sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml @@ -131,6 +131,8 @@ def load( filename:String, _compress:boolean ):scala.xml.Node = { val fAdapter = new scala.xml.BindingFactoryAdapter { + val namespace=<qstring ref="namespace"/>; + val f = { val res = new mutable.HashMap[String, (scala.xml.AttributeSeq,cT) => scala.xml.Node]() ; <elementBinding> diff --git a/sources/scala/xml/AttributeSeq.scala b/sources/scala/xml/AttributeSeq.scala index c04c96aa42..31bb5cf43c 100644 --- a/sources/scala/xml/AttributeSeq.scala +++ b/sources/scala/xml/AttributeSeq.scala @@ -26,6 +26,16 @@ object AttributeSeq { }:_* ) } + /** construct an attribute sequence from a map + * @param as a map from Pair(uri,key) to value + */ + final def fromUMap(as:Map[UName,String]) = { + AttributeSeq.fromAttrs( { + for( val a <- as.keys.toList ) + yield Attribute(a.uri,a.label, as(a)) + }:_* ) + } + /** construct from a map, fixing namespacePs to ns * each Attribute with an empty namespace will get the namespace ns. * @param ns the namespace to use instead of the empty one @@ -84,6 +94,12 @@ abstract class AttributeSeq with Seq[Attribute] { def sortedSeq:TreeSet[Attribute]; + override def equals(x: Any) = x match { + case that:AttributeSeq => (this.sortedSeq == that.sortedSeq) + case _ => false; + } + + final def length = sortedSeq.size; final def elements = sortedSeq.elements; final def apply(i:Int) = sortedSeq.elements.drop(i).next; @@ -101,6 +117,24 @@ abstract class AttributeSeq with Seq[Attribute] { return None; } + /** Return a new AttributeSeq with removed attributes + * Only namespace and label are regarded + * + * @param attrs the attributes to be removed + * @return a new AttributeSeq without attributes from attrs + */ + final def -(attrs: Attribute*) = { + val diff = new mutable.HashSet[Pair[String,String]]; + for(val a <- attrs) { + diff += Pair(a.namespace, a.key); + } + var newset = new TreeSet[Attribute]; + for(val a <- elements; !(diff contains Pair(a.namespace, a.key))) { + newset = newset + a; + } + new AttributeSeq { final def sortedSeq = newset }; + } + /** Return a new AttributeSeq with updated or added attributes * * @param attrs diff --git a/sources/scala/xml/BindingFactoryAdapter.scala b/sources/scala/xml/BindingFactoryAdapter.scala index 698be8b82c..9f63fb7cf6 100644 --- a/sources/scala/xml/BindingFactoryAdapter.scala +++ b/sources/scala/xml/BindingFactoryAdapter.scala @@ -16,8 +16,9 @@ import scala.collection.mutable.HashMap ; ** to the SAX XML parser, by giving concrete values for the factory maps f and g. */ -abstract class BindingFactoryAdapter extends FactoryAdapter() { +abstract class BindingFactoryAdapter extends FactoryAdapter() with NodeFactory[Node] { + val namespace:String; var errors = 0; /** mapping from element names to an element constructor @@ -46,7 +47,7 @@ abstract class BindingFactoryAdapter extends FactoryAdapter() { } // if compress is set, used for hash-consing - val cache = new HashMap[int,Node]; + //val cache = new HashMap[int,Node]; //var cacheCount = 0; @@ -54,10 +55,19 @@ abstract class BindingFactoryAdapter extends FactoryAdapter() { f.get( elemName ) match { case Some(d) => d case _ => { - throw new IllegalArgumentException("unrecognized:elemNamehello"); + throw new IllegalArgumentException("unrecognized:"+elemName); } } + protected def create(uname: UName, attrs: AttributeSeq, children:Seq[Node]): Node = { + if( this.namespace == uname.uri ) { + val c = getConstructor( uname.label ); + c( attrs, children ); + } else { + Elem( uname.uri, uname.label, attrs, children:_* ); + } + } + /** creates an element. see also compress */ def createNode(uri:String, elemName:String, @@ -65,6 +75,7 @@ abstract class BindingFactoryAdapter extends FactoryAdapter() { children:List[Node] ):Node = { val uri$ = uri.intern(); val attribs1 = AttributeSeq.fromMap(attribs); + // 2do:optimize if( !compress ) { // get constructor @@ -73,6 +84,8 @@ abstract class BindingFactoryAdapter extends FactoryAdapter() { } else { // do hash-consing val ahc = attribs.toList.hashCode(); + makeNode(UName(uri$, elemName), attribs1, children); + /* val h = Utility.hashCode( uri$, elemName, ahc, children ); cache.get( h ).match { @@ -88,6 +101,7 @@ abstract class BindingFactoryAdapter extends FactoryAdapter() { cache.update( h, el ); el } + */ } } // createNode diff --git a/sources/scala/xml/Node.scala b/sources/scala/xml/Node.scala index 0f8eb8535b..f7cde70a68 100644 --- a/sources/scala/xml/Node.scala +++ b/sources/scala/xml/Node.scala @@ -76,14 +76,14 @@ abstract class Node extends NodeSeq { override def equals( x:Any ):boolean = x match { case that:Node => //Console.print("(Node)"); - that.label == this.label && - that.attribute.sameElements( this.attribute ) && - that.child.sameElements( this.child ) // sameElements + that.label == this.label + && that.attributes == this.attributes + && that.child.sameElements( this.child ) // sameElements case _ => false } /** returns a hashcode */ - override def hashCode() = + override def hashCode(): Int = Utility.hashCode(namespace, label, attribute.toList.hashCode(), child); diff --git a/sources/scala/xml/NodeBuffer.scala b/sources/scala/xml/NodeBuffer.scala index 9fedfdb683..56b70afa86 100644 --- a/sources/scala/xml/NodeBuffer.scala +++ b/sources/scala/xml/NodeBuffer.scala @@ -33,6 +33,15 @@ class NodeBuffer extends scala.collection.mutable.ArrayBuffer[Node] { */ def +(ns: Iterable[Node]): NodeBuffer = { super.++(ns); this } + + /** + * Append a sequence of nodes to this buffer, returns reference on + * this NodeBuffer for convenience. + * + * @param ns + */ + def +(ns: Iterator[Node]): NodeBuffer = { ns.foreach{x => super.+(x)}; this } + /** * Append given string as a <code>scala.xml.Text</code> node to this * buffer, returns reference on this NodeBuffer for convenience. diff --git a/sources/scala/xml/NodeFactory.scala b/sources/scala/xml/NodeFactory.scala new file mode 100644 index 0000000000..d971865dad --- /dev/null +++ b/sources/scala/xml/NodeFactory.scala @@ -0,0 +1,67 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +** $Id $ +\* */ + +package scala.xml; + +import scala.collection.Map ; +import scala.collection.mutable ; + +abstract class NodeFactory[A <: Node] { + + val ignoreComments = false; + val ignoreProcInstr = false; + + /* default behaviour is to use hash-consing */ + val cache = new mutable.HashMap[int,List[A]](); + + + + protected def create(uname: UName, attrs: AttributeSeq, children:Seq[Node]): A; + + def makeNode(uname: UName, attrSeq:AttributeSeq, children:Seq[Node]): A = { + val hash = Utility.hashCode( uname, attrSeq.hashCode(), children ) ; + + def construct: A = { + val el = create( uname, attrSeq, children ); + cache.update( hash, List(el)); + el + } + + def nodeEquals(n: Node) = + (n.namespace == uname.uri) + &&(n.label == uname.label) + &&(n.attributes == attrSeq) + &&(n.child.sameElements(children)); + + cache.get( hash ) match { + case Some(list) => // find structurally equal + val it = list.elements; + val lookup = it.find { x => nodeEquals(x) }; + lookup match { + case Some(x) => x; // return cached elem + case _ => construct; + } + case _ => construct + } + } + + def makeText(s: String) = + Text( s ); + + def makeComment(s: String): Seq[Comment] = + if(ignoreComments) Nil else List(Comment( s )); + + def makeProcInstr(t: String, s: String): Seq[ProcInstr] = + if(ignoreProcInstr) Nil else List(ProcInstr(t, s)); + + def makeCharData(s: String) = + CharData( s ); + + +} diff --git a/sources/scala/xml/UName.scala b/sources/scala/xml/UName.scala new file mode 100644 index 0000000000..e1f05d3c07 --- /dev/null +++ b/sources/scala/xml/UName.scala @@ -0,0 +1,4 @@ +package scala.xml ; + +/** a universal name, like a qname after namespace prefix resolution */ +case class UName(uri: String, label: String); diff --git a/sources/scala/xml/Utility.scala b/sources/scala/xml/Utility.scala index 6c538109a9..9aec5a33b7 100644 --- a/sources/scala/xml/Utility.scala +++ b/sources/scala/xml/Utility.scala @@ -235,6 +235,11 @@ object Utility { } /** returns a hashcode for the given constituents of a node */ + def hashCode(uname: UName, attribHashCode: Int, children: Seq[Node]): Int = { + hashCode(uname.uri, uname.label, attribHashCode, children); + } + + /** returns a hashcode for the given constituents of a node */ def hashCode(uri: String, label: String, attribHashCode: Int, children: Seq[Node]) = { 41 * uri.hashCode() % 7 + label.hashCode() + attribHashCode + children.hashCode() } diff --git a/sources/scala/xml/nobinding/NoBindingFactoryAdapter.scala b/sources/scala/xml/nobinding/NoBindingFactoryAdapter.scala index 189a1f5208..ee1882cd57 100644 --- a/sources/scala/xml/nobinding/NoBindingFactoryAdapter.scala +++ b/sources/scala/xml/nobinding/NoBindingFactoryAdapter.scala @@ -15,7 +15,7 @@ import org.xml.sax.InputSource; /** nobinding adaptor providing callbacks to parser to create elements. * implements hash-consing */ -class NoBindingFactoryAdapter extends FactoryAdapter { +class NoBindingFactoryAdapter extends FactoryAdapter with NodeFactory[Elem] { type Elem = scala.xml.Elem; @@ -25,12 +25,17 @@ class NoBindingFactoryAdapter extends FactoryAdapter { **/ def nodeContainsText( label:java.lang.String ):boolean = true; + + protected def create(uname: UName, attrs: AttributeSeq, children:Seq[Node]): Elem = { + Elem( uname.uri, uname.label, attrs, children:_* ); + } + /* default behaviour is to use hash-consing */ - val cache = new mutable.HashMap[int,Elem](); + //val cache = new mutable.HashMap[int,Elem](); /** creates a node. never creates the same node twice, using hash-consing */ - def createNode(uri:String, label: String, attrs: mutable.HashMap[Pair[String,String],String], children: List[Node] ):Elem = { + def createNode(uri:String, label: String, attrs: mutable.HashMap[Pair[String,String],String], children: List[Node] ): Elem = { // this is a dirty hack to quickly add xmlns. // does SAX handle prefixes, xmlns stuff ? @@ -43,6 +48,8 @@ class NoBindingFactoryAdapter extends FactoryAdapter { val attrSeq = AttributeSeq.fromMap( uri$, attrs ); val elHashCode = Utility.hashCode( uri$, label, attrSeq.hashCode(), children ) ; + makeNode(UName(uri$,label),attrSeq, children); + /* cache.get( elHashCode ).match{ case Some(cachedElem) => //System.err.println("[using cached elem +"+cachedElem.toXML+"!]"); //DEBUG @@ -52,6 +59,7 @@ class NoBindingFactoryAdapter extends FactoryAdapter { cache.update( elHashCode, el ); el } + */ } /** creates a text node |