From 6c1888cb456c1fd87594399ca9cdeec4485dfaac Mon Sep 17 00:00:00 2001 From: buraq Date: Fri, 12 Mar 2004 20:08:43 +0000 Subject: changes to xml api --- sources/scala/tools/dtd2scala/DeclToScala.scala | 8 +- sources/scala/xml/Elem.scala | 53 ++++---- sources/scala/xml/Node.scala | 160 +++++++++++------------- sources/scala/xml/Text.scala | 15 +-- sources/scala/xml/Utility.scala | 8 +- test/files/jvm/xmlstuff.check | 10 ++ test/files/jvm/xmlstuff.scala | 140 ++++++++++++--------- 7 files changed, 207 insertions(+), 187 deletions(-) diff --git a/sources/scala/tools/dtd2scala/DeclToScala.scala b/sources/scala/tools/dtd2scala/DeclToScala.scala index 95d3f94d71..4283fbba46 100644 --- a/sources/scala/tools/dtd2scala/DeclToScala.scala +++ b/sources/scala/tools/dtd2scala/DeclToScala.scala @@ -40,7 +40,7 @@ class DeclToScala(fOut:PrintWriter, case "template" => { lookup.update("objectName", objectName); lookup.update("compressDefault", compress.toString()); - n.children.elements.foreach { n => writeNode(n) } + n.child.elements.foreach { n => writeNode(n) } } case "elementBinding" => { for( val decl <- elemMap.values.elements ) { @@ -48,7 +48,7 @@ class DeclToScala(fOut:PrintWriter, lookup += "elementContainsText" -> decl.containsText.toString(); lookup += "elementContentModel" -> decl.contentModel; curAttribs = decl.attribs; - n.children.elements.foreach{ n => writeNode( n ) } + n.child.elements.foreach{ n => writeNode( n ) } } curAttribs = null; lookup -= "elementName"; @@ -58,7 +58,7 @@ class DeclToScala(fOut:PrintWriter, case "attributeAssign" => { for( val aDecl <- curAttribs.keys.elements ) { lookup += "attributeName" -> aDecl; - n.children.elements.foreach{ n => writeNode( n ) } + n.child.elements.foreach{ n => writeNode( n ) } } lookup -= "attributeName"; } @@ -66,7 +66,7 @@ class DeclToScala(fOut:PrintWriter, case "attributeBinding" => { for( val aDecl <- curAttribs.keys.elements ) { lookup += "attributeName" -> aDecl; - n.children.elements.foreach{ n => writeNode( n ) } + n.child.elements.foreach{ n => writeNode( n ) } } lookup -= "attributeName"; } diff --git a/sources/scala/xml/Elem.scala b/sources/scala/xml/Elem.scala index 950a85f49f..bd4aabb054 100644 --- a/sources/scala/xml/Elem.scala +++ b/sources/scala/xml/Elem.scala @@ -1,39 +1,42 @@ package scala.xml ; -import scala.collection.immutable.{Map,ListMap} ; +import scala.collection.mutable.HashMap ; -case class Elem( name:String, children:Node* ) extends AttributedNode { +case class Elem( label:String, child:Node* ) extends Node with Similarity { - /** Returns the symbol name as a string. - */ - def label:String = name; + def similar( x:Any ) = { + x match { + case that:Node => (label == that.label) && child.similar( that.child ) + case _ => false; + } + } - /** Returns the list of children of this symbol. - def children: NodeSeq = new NodeSeq( List.fromIterator( - elems.elements map ( x => x match { - case n:Node => n; - case _ => Text(x.toString()); - }))); - */ + private val hmap = new HashMap[String,String](); - /** Returns a map representing the attributes of this node. + /** the attributes axis - default is Nil */ - def attributes: Map[String, String] = ListMap.Empty; + def attribute: Seq[Pair[String, String]] = hmap.elements.toSeq( hmap.size ); - /** returns a new symbol with updated attributes + /** returns a new element with updated attributes */ - final def %(attrs: List[Pair[String, String]]) = - new Elem( name, children:_* ) { - val themap = Elem.this.attributes.incl( attrs ); - override def attributes = themap; + final def %(attrs: Seq[Pair[String, String]]) = { + val newmap = new HashMap[String,String](); + for( val p <- hmap.elements ) { newmap += p._1 -> p._2 }; + for( val p <- attrs ) { newmap += p._1 -> p._2 }; + new Elem( label, child:_* ) { + private val hmap = newmap; + //override def attribute = newmap.elements.toSeq( newmap.size ); }; - + } /** returns a new symbol with updated attribute */ - final def %(attr: Pair[String, String]) = - new Elem( name, children:_* ) { - val themap = Elem.this.attributes.incl( attr ); - override def attributes = themap; + final def %(attr: Pair[String, String]) = { + val newmap = new HashMap[String,String](); + for( val p <- hmap.elements ) { newmap += p._1 -> p._2 }; + newmap += attr._1 -> attr._2; + new Elem( label, child:_* ) { + private val hmap = newmap; + //override def attribute = newmap.elements.toSeq( newmap.size ); }; - + } } diff --git a/sources/scala/xml/Node.scala b/sources/scala/xml/Node.scala index f050b35dc1..00c5d88549 100644 --- a/sources/scala/xml/Node.scala +++ b/sources/scala/xml/Node.scala @@ -9,108 +9,90 @@ package scala.xml ; +import scala.collection.mutable.AppendBuffer ; -/** Trait for representation of XML elements. These are created by - * a dtd2scala binding tool +/** Trait for representing XML using nodes of a labelled tree. + * This trait contains an implementation of a subset of XPath for navigation. */ trait Node { - /** the label of this XML node */ - def label: String; - /** the children of this XML node */ - def children: Seq[Node]; - /** the string representation of this XML node */ - def toXML: String; - /** projection function. Similar to XPath, use this./'foo to get a list + /** QName (the label of this node). I.e. "foo" for <foo/>) */ + def label: String; + + /** attribute axis */ + def attribute: Seq[ Pair[String,String] ]; + + final def apply(key: String): Option[String] = { + val it = attribute.elements.filter { x => key == x._1 }; + if( it.hasNext ) Some( it.next._2 ) else None + } + + /** child axis (all children of this node) */ + def child: Seq[Node]; + + /** descendant axis (all descendants of this node) */ + def descendant:Seq[Node] = child.toList.flatMap { + x => x::x.descendant.asInstanceOf[List[Node]] + } ; + + /** descendant axis (all descendants of this node) */ + def descendant_or_self:Seq[Node] = this::child.toList.flatMap { + x => x::x.descendant.asInstanceOf[List[Node]] + } ; + + override def equals( x:Any ):boolean = x match { + case that:Node => + //Console.print("(Node)"); + that.label == this.label && + that.attribute.similar( this.attribute ) && + that.child.similar( this.child ) + case _ => false + } + + /** projection function. Similar to XPath, use this \ 'foo to get a list * of all children of this node that are labelled with "foo". * The document order is preserved. */ - def |(that:Symbol): NodeSeq = new NodeSeq({ - val iter = children.elements; - if( "_" == that.name ) { - List.fromIterator( iter ); - } else { - var res:List[Node] = Nil; - for( val x <- iter; x.label == that.name ) { - res = x::res; - } - res.reverse + def \(that:Symbol): NodeSeq = { + new NodeSeq({ + val iter = child.elements; + that.name match { + + case "_" => iter.toList; + case _ => + var res:List[Node] = Nil; + for( val x <- child.elements; x.label == that.name ) { + res = x::res; + } + res.reverse } }); + } - /** projection function. Similar to XPath, use this./#'foo to get a list - * of all descendants of this node that are labelled with "foo". - * Use /'_ as a wildcard. + /** projection function. Similar to XPath, use this \\ 'foo to filter + * all nodes labelled with "foo" from the descendant_or_self axis. * The document order is preserved. */ - def ||(that:Symbol): NodeSeq = new NodeSeq({ - var res:List[Node] = Nil; - var tmp:List[Node] = Nil; - for( val x <- children.elements ) { - if ( x.label == that.name || "_" == that.name ) - tmp = x::tmp; - tmp = tmp:::(x||(that)).toList; - res = res:::tmp; - tmp = Nil - } - res; - }); - -} - -/* a wrapper that adds a filter method */ -class NodeSeq(theList:List[Node]) extends Seq[Node] { - val res = theList.flatMap ( x => List.fromIterator( x.children.elements )); - - /** projection function. Similar to XPath, use this./'foo to get a list - * of all elements of this sequence that are labelled with "foo". - * Use /'_ as a wildcard. The document order is preserved. - */ - def |(that: Symbol) = if( "_" == that.name ) { - new NodeSeq( res ) - } else { - new NodeSeq( res.filter( y => y.label == that.name )) + def \\(that:Symbol): NodeSeq = { + new NodeSeq( + that.name match { + case "_" => this.descendant_or_self; + case _ => this.descendant_or_self.asInstanceOf[List[Node]]. + filter( x => x.label == that.name ); + /* + val res = new AppendBuffer[Node](); + if( this.label == that.name ) + res.append( this ); + res.append( this.child.elements.flatMap { + x => //x.\\(that).elements + }.toSeq); + res.toList + */ + }) } + override def hashCode() = Utility.hashCode(label, attribute.toList.hashCode(), child); + /** string representation of this node */ + override def toString() = Utility.toXML(this); - /** projection function. Similar to XPath, use this./'foo to get a list - * of all children of this node that are labelled with "foo" - * Use ||'_ as a wildcard. The document order is preserved. - */ - def ||(that: Symbol): NodeSeq = new NodeSeq( - if ( "_" == that.name ) { - theList.flatMap ( x => (x||'_).toList ) - } else { - theList.flatMap ( x => { - if( x.label == that.name ) - x::(x||(that)).toList; - else - (x||(that)).toList; - }) - }); - - override def toList:List[Node] = theList; - - /* Seq methods */ - def length = theList.length; - def elements = theList.elements ; - def apply( i:int ) = theList.apply( i ); - /* forwarding list methods - def isEmpty: boolean = theList.isEmpty; - def head: Node = theList.head; - def tail: List[Node] = theList.tail; - - override def toString():String = "Node"+theList.toString(); - - override def filter(p: Node => Boolean): NodeList = - new NodeList( theList.filter( p ) ); - - override def foreach(f: Node => Unit): Unit = theList.foreach( f ); - - override def flatMap[b](f: Node => List[b]): List[b] = theList.flatMap( f ); - - override def :::[b >: Node](prefix: List[b]): List[b] = theList.:::( prefix ); - */ - - //the == method cannot be forwarded :-( } diff --git a/sources/scala/xml/Text.scala b/sources/scala/xml/Text.scala index bb1ec0354c..1c5ab0ddb2 100644 --- a/sources/scala/xml/Text.scala +++ b/sources/scala/xml/Text.scala @@ -12,6 +12,7 @@ package scala.xml; import scala.collection.Map ; /** an XML node for text (PCDATA). Used in both non-bound and bound XML representations + * @author Burak Emir * @param text the text contained in this node **/ @@ -21,19 +22,15 @@ case class Text( text:String ) extends Node { */ def label = "#PCDATA"; - /** always returns an empty list - */ - final def children = Nil; + /** always empty */ + final def attribute = Nil; + /** always empty */ + final def child = Nil; override def hashCode() = text.hashCode(); - /** returns "Text("+raw text+")" - */ + /** returns text, with some characters escaped according to XML spec */ override def toString() = Utility.escape( text ); - /** returns PCDATA text, with some characters escaped according to XML spec - */ - override def toXML = Utility.escape( text ); - } diff --git a/sources/scala/xml/Utility.scala b/sources/scala/xml/Utility.scala index fd9eda8e5d..818df1b0b6 100644 --- a/sources/scala/xml/Utility.scala +++ b/sources/scala/xml/Utility.scala @@ -37,15 +37,15 @@ object Utility { def toXML( n:Node ):String = n match { case Text( t ) => escape( t ); - case x:AttributedNode => { + case x:Node => { val s = new StringBuffer(); s.append('<'); s.append( x.label ); - if( null != x.attributes ) { - s.append( attr2xml( x.attributes.elements ) );{} + if( x.attribute.length != 0 ) { + s.append( attr2xml( x.attribute.elements ) );{} } s.append('>'); - s.append( toXML( x.children.elements ) ); + s.append( toXML( x.child.elements ) ); s.append("'); diff --git a/test/files/jvm/xmlstuff.check b/test/files/jvm/xmlstuff.check index fafc444191..8fb144e796 100644 --- a/test/files/jvm/xmlstuff.check +++ b/test/files/jvm/xmlstuff.check @@ -1,11 +1,21 @@ +equality passed ok passed ok passed ok passed ok passed ok +xpath \ passed ok passed ok passed ok passed ok passed ok passed ok +case _ +passed ok +case _ +passed ok +xpath \\ +passed ok +passed ok +passed ok diff --git a/test/files/jvm/xmlstuff.scala b/test/files/jvm/xmlstuff.scala index db6e3f90a0..ebd140d301 100644 --- a/test/files/jvm/xmlstuff.scala +++ b/test/files/jvm/xmlstuff.scala @@ -2,70 +2,93 @@ import java.io.StringReader; import org.xml.sax.InputSource; import scala.xml.nobinding.XML; import scala.testing.UnitTest._ ; -import scala.xml.{Node,NodeSeq}; +import scala.xml.{Node,NodeSeq,Text}; object Test with Application { - - def eq( a:Seq[Node], b:Seq[Node] ) = { - if( a.length == b.length ) { - val ita = a.elements; - val itb = b.elements; - var res = true; - while( ita.hasNext ) { - res = res &&( ita.next == itb.next ); - }; - res - } else { - false - } +/* + def eq( a:Seq[Node], b:Seq[Node] ):boolean = { + (a.length == b.length) && eq(a.elements,b.elements) + } + def eq( ita:Iterator[Node], itb:Iterator[Node] ) = { + var res = true; + while( ita.hasNext && itb.hasNext && res ) { + res = (ita.next == itb.next); + }; + !ita.hasNext && !itb.hasNext && res } + */ val xmlFile1 = ""; val isrc1 = new InputSource( new StringReader( xmlFile1 ) ); val parsedxml1 = XML.load( isrc1 ); + val isrc11 = new InputSource( new StringReader( xmlFile1 ) ); + val parsedxml11 = XML.load( isrc11 ); + + val c = new Node { + def label = "hello"; + def child = List('world()); + def attribute = List(); + }; + + Console.println("equality"); + assertEquals( c, parsedxml11 ); + assertEquals( parsedxml1, parsedxml11 ); + assertSimilar( List(parsedxml1), List(parsedxml11)); + assertSimilar( Iterator.fromArray(Predef.Array(parsedxml1)).toSeq(1), List(parsedxml11)); + + val x2 = "Peter BunemanDan SuciuData on ze web"; + + val i = new InputSource( new StringReader( x2 )); + val x2p = XML.load( i ); + + assertSimilar(x2p, 'book('author(Text("Peter Buneman")), + 'author(Text("Dan Suciu")), + 'title(Text("Data on ze web")))); val xmlFile2 = "Peter BunemanDan SuciuData on ze webJohn MitchellFoundations of Programming Languages"; val isrc2 = new InputSource( new StringReader( xmlFile2 ) ); val parsedxml2 = XML.load( isrc2 ); // xmlFile2/book -> book,book + Console.println("xpath \\"); - assertEquals( eq( parsedxml1/'_ ,List('world()) ), true); - assertEquals( eq( parsedxml1/'world ,List('world()) ), true); - assertEquals( - eq( + assertSimilar( parsedxml1 \ '_ , List( 'world() ) ); - parsedxml2/'_, + assertSimilar( parsedxml1 \ 'world, List( 'world() ) ); + +/* + Console.println( parsedxml2 \ '_ ); + Console.println( (parsedxml2 \ '_).elements); + for( val i <- (parsedxml2 \ '_).elements) { + Console.println( i ); + }; + */ + assertSimilar( + parsedxml2 \ '_ , List( 'book('author(Text("Peter Buneman")), 'author(Text("Dan Suciu")), 'title(Text("Data on ze web"))), 'book('author(Text("John Mitchell")), - 'title(Text("Foundations of Programming Languages"))) - )), true ); - + 'title(Text("Foundations of Programming Languages")))) + ); + assertEquals( (parsedxml2 \ 'author).length, 0 ); - assertEquals( (parsedxml2/'author).length == 0, true ); - - - assertEquals( - eq( - - parsedxml2/'book, + assertSimilar( + parsedxml2 \ 'book, List( 'book('author(Text("Peter Buneman")), 'author(Text("Dan Suciu")), 'title(Text("Data on ze web"))), 'book('author(Text("John Mitchell")), - 'title(Text("Foundations of Programming Languages"))) - )), true ); + 'title(Text("Foundations of Programming Languages")))) + ); - assertEquals( - eq( + assertSimilar( - parsedxml2/'_/'_, + parsedxml2 \ '_ \ '_, List('author(Text("Peter Buneman")), 'author(Text("Dan Suciu")), @@ -73,41 +96,48 @@ object Test with Application { 'author(Text("John Mitchell")), 'title(Text("Foundations of Programming Languages"))) - ), true); + ); - assertEquals( - eq( + assertSimilar( - parsedxml2/'_/'author, + parsedxml2 \ '_ \ 'author, List('author(Text("Peter Buneman")), 'author(Text("Dan Suciu")), 'author(Text("John Mitchell"))) - ), true); + ); + + assertSimilar( (parsedxml2 \ '_ \ '_ \ 'author), List() ); - assertEquals( (parsedxml2/'_/'_/'author).length == 0, true ); + Console.println("xpath \\\\"); - assertEquals( - eq( + assertSimilar( - parsedxml2/#'author, + parsedxml2 \\ 'author, List('author(Text("Peter Buneman")), 'author(Text("Dan Suciu")), 'author(Text("John Mitchell"))) - ), true ); + ); - assertEquals( - eq( + assertSimilar( - parsedxml2/#'_, + new NodeSeq(List( parsedxml2 ))\\ '_, List( - 'book('author(Text("Peter Buneman")), - 'author(Text("Dan Suciu")), - 'title(Text("Data on ze web"))), + 'bib( + 'book( + 'author(Text("Peter Buneman")), + 'author(Text("Dan Suciu")), + 'title(Text("Data on ze web"))), + 'book('author(Text("John Mitchell")), + 'title(Text("Foundations of Programming Languages")))), + 'book( + 'author(Text("Peter Buneman")), + 'author(Text("Dan Suciu")), + 'title(Text("Data on ze web"))), 'author(Text("Peter Buneman")), Text("Peter Buneman"), 'author(Text("Dan Suciu")), @@ -120,17 +150,15 @@ object Test with Application { Text("John Mitchell"), 'title(Text("Foundations of Programming Languages")), Text("Foundations of Programming Languages")) - ) , true); + ); - assertEquals( - eq( + assertSimilar( - parsedxml2/#'title, + parsedxml2 \\ 'title, List( 'title(Text("Data on ze web")), 'title(Text("Foundations of Programming Languages"))) - ) , true); - +); } -- cgit v1.2.3