diff options
-rw-r--r-- | sources/scala/xml/Element.scala | 83 | ||||
-rw-r--r-- | sources/scala/xml/Generic.scala | 24 | ||||
-rw-r--r-- | sources/scala/xml/PCDATA.scala | 6 | ||||
-rw-r--r-- | sources/scala/xml/ScalaFactoryAdapter.scala | 66 |
4 files changed, 98 insertions, 81 deletions
diff --git a/sources/scala/xml/Element.scala b/sources/scala/xml/Element.scala index 0dce66ab1b..f604d5f7c2 100644 --- a/sources/scala/xml/Element.scala +++ b/sources/scala/xml/Element.scala @@ -2,72 +2,51 @@ package scala.xml ; import javaAdapter.Map; -/** interface to XML elements. used by dtd2scala tool and the generated XML parser interfaces. - * sorry, no attributes yet (needs working HashMap). - * future revisions might use sequence instead of list. - */ - +/** superclass for specific representation of XML elements. These are created by the dtd2scala tool, together +* with a parsing facility. +*/ abstract class Element { - def getName: String; // the real element name - def getChildren: Seq[ Element ]; // the children - def setChildren( l:Seq[ Element ] ):Unit ; - def getAttribs: Map[ String, String ]; // disabled - def setAttribs( m:Map[ String, String ] ):Unit ; + def getName: String; // the real element name + def getChildren: Seq[ Element ]; // the children + def setChildren( l:Seq[ Element ] ):Unit ; + def getAttribs: Map[ String, String ]; // disabled + def setAttribs( m:Map[ String, String ] ):Unit ; - override def hashCode() = Element.hashValue( getName, getAttribs, getChildren ); + /** see Element.hashValue + */ - def toXML: String = { - "<" + getName + Generic.toXML( getAttribs ) + ">" - + toXML_( getChildren ) - + "</" + getName +">" - } + override def hashCode() = Element.hashValue( getName, getAttribs, getChildren ); - def toXML_( elems:Seq[Element] ):String = elems match { - case head :: tail => head.toXML + toXML_( tail ); - case Nil => ""; - } + def toXML: String = { + "<" + getName + Generic.toXML( getAttribs ) + ">" + + toXML_( getChildren ) + + "</" + getName +">" + } - /* - def toXML_( attrib:Map[ String, String ] ):String = { - def iterate( keys:Iterator[String] ) = - if( keys.hasNext ) - { - val key = keys.next; - " " + key + "=\"" + attrib.get( key ) + "\" "; - } - else - { - "" - } + def toXML_( elems:Seq[Element] ):String = elems match { + case head :: tail => head.toXML + toXML_( tail ); + case Nil => ""; + } - if( attrib != null ) iterate( attrib.keys.elements ) else ""; - } -*/ - override def toString() = getName.concat("(").concat(getChildren.toString().concat(")")); + override def toString() = getName.concat("(").concat(getChildren.toString().concat(")")); - /* - def toXML : String = { - val attribs = getAttribs; - var attribStr = ""; - if( attribs != null ) - attribStr = scala.xml.util.toXML( attribs ) - else - () ; - "<" + getName - + attribStr - + ">" - + scala.xml.util.toXML( getChildren ) - + "</" + getName + ">" ; - } // def toXML -*/ -} // abstract class +} // abstract class Element +/** static helper methods for specific representations of XML elemens +*/ object Element { + + /** returns a hash value computed from the element name, attributes and hash values of children. + */ + def hashValue( name:String, attribs:Map[ String, String ], children:Seq[ Element ] ) = { name.hashCode() + attribs.hashCode() + children.hashCode() } + /** returns a hash value computed from the element name, attributes and hash values of children. + */ + def hashValue( name:String, attribs:java.util.Map, children:Seq[ Element ] ) = { name.hashCode() + attribs.hashCode() + children.hashCode() } diff --git a/sources/scala/xml/Generic.scala b/sources/scala/xml/Generic.scala index fd2628aeb1..87344d101f 100644 --- a/sources/scala/xml/Generic.scala +++ b/sources/scala/xml/Generic.scala @@ -13,12 +13,18 @@ object Generic { // utility functions + /** TEMPORARY converting Java iterators to scala List + */ + def iterToList[ a ]( iter:java.util.Iterator ):List[a] = if( !iter.hasNext() ) Nil else (iter.next().asInstanceOf[ a ])::iterToList( iter ) ; + /** TEMPORARY converting Java maps to javaAdapter maps + */ + def mapToMap[a,b]( map:java.util.Map ):Map[a,b] = { val keys:java.util.Iterator = map.keySet().iterator(); @@ -37,6 +43,9 @@ object Generic { res } + /** turns a Map that contains attributes into XML like att1="val1" att2="val2" + */ + def toXML( attrib:Map[ String, String ] ):String = { def iterate( keys:Iterator[String] ) = if( keys.hasNext ) { @@ -51,6 +60,9 @@ object Generic { // attributes + /** this trait is mixed in with Labelled in order to provide attributes + */ + trait Attribbed { // only CDATA / String attributes for now @@ -59,11 +71,18 @@ object Generic { } // functions for generic xml loading, saving + /** will load the given file and return a generic XML representation + */ + def load( filename:String ):Labelled = { val b = new GenericFactoryAdapter().loadXML( filename ); b.asInstanceOf[Labelled] }; + /** will save a generic XML representation doc to filename. Uses NIO classes of JDK 1.4 for character conversion, + * encoding is fixed to ISO-8859-1 for now. + */ + def save( filename:String, doc:Any ):Unit = { import java.io.{FileOutputStream,Writer}; import java.nio.channels.{Channels,FileChannel}; @@ -95,6 +114,11 @@ object Generic { fos.close(); } + /** this class contains methods called back by the parser to create elements. + * It implements hash-consing, i.e. identical elemens (same tag, same attributes, same children) + * are only constructed once ! + */ + class GenericFactoryAdapter extends FactoryAdapter() { def elementContainsText( name:java.lang.String ):boolean = true; diff --git a/sources/scala/xml/PCDATA.scala b/sources/scala/xml/PCDATA.scala index 5b9aa01c1a..8f21d11309 100644 --- a/sources/scala/xml/PCDATA.scala +++ b/sources/scala/xml/PCDATA.scala @@ -4,6 +4,9 @@ package scala.xml; import scala.xml.javaAdapter.Map ; +/** an XML representation text. Used in both generic and specific XML representation +*/ + case class PCDATA( content:String ) extends Element { def getName = "PCDATA"; @@ -12,6 +15,9 @@ case class PCDATA( content:String ) extends Element { def getAttribs = error("PCDATA.getAttribs"); def setAttribs( m:Map[ String, String ] ):Unit = error("PCDATA.setAttribs"); + /** like toString, but escaping the characters < > & and " as demanded by XML standard. + */ + override def toXML:String = { // new java.util.StringBuffer !!crashes!! val s = new StringBuffer(); diff --git a/sources/scala/xml/ScalaFactoryAdapter.scala b/sources/scala/xml/ScalaFactoryAdapter.scala index 600357b6cd..58c60776cb 100644 --- a/sources/scala/xml/ScalaFactoryAdapter.scala +++ b/sources/scala/xml/ScalaFactoryAdapter.scala @@ -13,18 +13,23 @@ import scala.xml.javaAdapter.HashMap ; abstract class ScalaFactoryAdapter extends FactoryAdapter() { - /** a mapping from a element name (string) to an element constructor + /** subclasses need to provide a mapping from a element name (string) to an element constructor * (constr:Seq[Element] => Element) */ val f: Map[ String, Seq[Element] => Element ]; - /** a mapping from an element name (string) to a truth value indicating + /** subclasses need to provide a mapping from an element name (string) to a truth value indicating * whether text (PCDATA) may appear as */ val g: Map[ String, boolean ] ; - val compress: boolean ; + /** subclasses need to tell whether they want to use hash-consing, which creates only non-identical elements + */ + val compress: boolean ; + + /** looks up in g whether an element may contain text (PCDATA) + */ def elementContainsText( name:java.lang.String ):boolean = g.get( name ) ; @@ -32,33 +37,36 @@ abstract class ScalaFactoryAdapter // if compress is set, used for hash-consing val cache = new HashMap(); - def createElement(elemName:String, - attribs:java.util.Map, - children:java.util.Iterator ):scala.Object = { - val _children = Generic.iterToList[Element]( children ); // 2do:optimize - if( !compress ) { - val c = f.get( elemName ); // get constructor - val el = c( _children ); - el.setAttribs( Generic.mapToMap[String,String]( attribs ) ); - el - } else { // do hash-consing + /** creates an element. uses hash-consing if compress == true + */ + def createElement(elemName:String, + attribs:java.util.Map, + children:java.util.Iterator ):scala.Object = { + val _children = Generic.iterToList[Element]( children ); // 2do:optimize + if( !compress ) { + val c = f.get( elemName ); // get constructor + val el = c( _children ); + el.setAttribs( Generic.mapToMap[String,String]( attribs ) ); + el + } else { // do hash-consing - val h = Element.hashValue( elemName, attribs, _children ); - val el_cache = cache.get( h.asInstanceOf[scala.All] ).asInstanceOf[scala.Object]; - if ( el_cache != null ) { // return cached elem - el_cache - } else { - val c = f.get( elemName ); // get constructor - val el = c( _children ); - el.setAttribs( Generic.mapToMap[String,String]( attribs ) ); - cache.put( h.asInstanceOf[scala.All], el.asInstanceOf[scala.All] ); - el - } - } - } + val h = Element.hashValue( elemName, attribs, _children ); + val el_cache = cache.get( h.asInstanceOf[scala.All] ).asInstanceOf[scala.Object]; + if ( el_cache != null ) { // return cached elem + el_cache + } else { + val c = f.get( elemName ); // get constructor + val el = c( _children ); + el.setAttribs( Generic.mapToMap[String,String]( attribs ) ); + cache.put( h.asInstanceOf[scala.All], el.asInstanceOf[scala.All] ); + el + } + } + } - def createPCDATA( text:String ):scala.Object = { - new PCDATA( text ); - }; + /** creates PCDATA element */ + def createPCDATA( text:String ):scala.Object = { + new PCDATA( text ); + }; } // ScalaFactoryAdapter |