summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorburaq <buraq@epfl.ch>2005-04-24 22:29:02 +0000
committerburaq <buraq@epfl.ch>2005-04-24 22:29:02 +0000
commit040ca6168b6c24482276903503b87eaa364ca416 (patch)
treea4bf6ef58fe6c1f6cf75e60fa33a64d1356c4460
parent67290d08794a237841dca5cfcb3fda7c05d22cdf (diff)
downloadscala-040ca6168b6c24482276903503b87eaa364ca416.tar.gz
scala-040ca6168b6c24482276903503b87eaa364ca416.tar.bz2
scala-040ca6168b6c24482276903503b87eaa364ca416.zip
moved files to other directories
-rw-r--r--sources/scala/xml/XML.scala75
-rw-r--r--sources/scala/xml/factory/LoggedNodeFactory.scala78
-rw-r--r--sources/scala/xml/factory/NodeFactory.scala77
-rw-r--r--sources/scala/xml/parsing/FactoryAdapter.scala344
-rw-r--r--sources/scala/xml/parsing/NoBindingFactoryAdapter.scala53
5 files changed, 627 insertions, 0 deletions
diff --git a/sources/scala/xml/XML.scala b/sources/scala/xml/XML.scala
new file mode 100644
index 0000000000..1fadac7fe8
--- /dev/null
+++ b/sources/scala/xml/XML.scala
@@ -0,0 +1,75 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+** $Id$
+\* */
+package scala.xml ;
+
+import scala.xml.parsing.NoBindingFactoryAdapter ;
+import org.xml.sax.InputSource;
+
+// import scala.xml.Utility ;
+
+/** functions to load and save XML elements. use this when data binding is not
+** desired, i.e. when XML is handled using Symbol nodes
+**/
+object XML {
+
+ import java.io._ ;
+
+ // functions for generic xml loading, saving
+
+ /** loads XML from given file */
+ final def loadFile( file: File ): scala.xml.Elem =
+ new NoBindingFactoryAdapter().loadXML( new InputSource(
+ new FileInputStream( file )
+ ));
+
+ /** loads XML from given file descriptor */
+ final def loadFile( fileDesc: FileDescriptor ): scala.xml.Elem =
+ new NoBindingFactoryAdapter().loadXML( new InputSource(
+ new FileInputStream( fileDesc )
+ ));
+
+ /** loads XML from given file */
+ final def loadFile( fileName:String ): scala.xml.Elem =
+ new NoBindingFactoryAdapter().loadXML( new InputSource(
+ new FileInputStream( fileName )
+ ));
+
+ /** loads XML from given InputStream */
+ final def load( is:InputStream ): scala.xml.Elem =
+ new NoBindingFactoryAdapter().loadXML( new InputSource( is ));
+
+ /** loads XML from given Reader */
+ final def load( reader:Reader ): scala.xml.Elem =
+ new NoBindingFactoryAdapter().loadXML( new InputSource( reader ));
+
+ /** loads XML from given sysID */
+ final def load( sysID:String ): scala.xml.Elem =
+ new NoBindingFactoryAdapter().loadXML( new InputSource( sysID ));
+
+ /** loads XML from a given input source*/
+ final def load( source:InputSource ): scala.xml.Elem =
+ new NoBindingFactoryAdapter().loadXML( source );
+
+ /** saves XML to filename with encoding ISO-8859-1 */
+ final def save( filename:String, doc:Elem ):Unit = {
+ /* using NIO classes of JDK 1.4 */
+ import java.io.{FileOutputStream,Writer};
+ import java.nio.channels.{Channels,FileChannel};
+
+ val fos = new FileOutputStream( filename );
+ val w:Writer = Channels.newWriter( fos.getChannel(), "ISO-8859-1" );
+
+ /* 2do: optimize by giving writer parameter to toXML*/
+ w.write( Utility.toXML( doc ));
+
+ w.close();
+ fos.close();
+ }
+
+}
diff --git a/sources/scala/xml/factory/LoggedNodeFactory.scala b/sources/scala/xml/factory/LoggedNodeFactory.scala
new file mode 100644
index 0000000000..cb57069ac2
--- /dev/null
+++ b/sources/scala/xml/factory/LoggedNodeFactory.scala
@@ -0,0 +1,78 @@
+package scala.xml.factory;
+
+/** This class logs what the nodefactory is actually doing.
+If you want to see what happens during loading, use it like this:
+object testLogged with Application {
+
+ val x = new scala.xml.nobinding.NoBindingFactoryAdapter
+ with scala.xml.LoggedNodeFactory[scala.xml.Elem]()
+ with scala.util.logging.ConsoleLogger;
+
+ Console.println("Start");
+
+ val doc = x.loadXML(new org.xml.sax.InputSource("http://lamp.epfl.ch/~buraq"));
+
+ Console.println("End");
+
+ Console.println(doc);
+}
+
+*/
+abstract class LoggedNodeFactory[A <: Node]
+extends NodeFactory[A]
+with scala.util.logging.Logged {
+
+ // configuration values;
+ val logNode = true;
+ val logText = false;
+ val logComment = false;
+ val logProcInstr = false;
+
+ final val NONE = 0;
+ final val CACHE = 1;
+ final val FULL = 2;
+ /** 0 = no loggging, 1 = cache hits, 2 = detail */
+ val logCompressLevel = 1;
+
+ // methods of NodeFactory
+
+ /** logged version of makeNode method */
+ override def makeNode(pre:String, label:String, attrSeq:MetaData, scope: NamespaceBinding, children:Seq[Node]): A = {
+ if(logNode)
+ log("[makeNode for "+label+"]");
+
+ val hash = Utility.hashCode(pre, label, attrSeq.hashCode(), scope.hashCode(), children) ;
+
+ /*
+ if(logCompressLevel >= FULL) {
+ log("[hashcode total:"+hash);
+ log(" elem name "+uname+" hash "+ ? ));
+ log(" attrs "+attrSeq+" hash "+attrSeq.hashCode());
+ log(" children :"+children+" hash "+children.hashCode());
+ }
+ */
+ if(!cache.get( hash ).isEmpty && (logCompressLevel >= CACHE))
+ log("[cache hit !]");
+
+ super.makeNode(pre, label, attrSeq, scope, children);
+ }
+
+ override def makeText(s: String) = {
+ if(logText)
+ log("[makeText:\""+s+"\"]");
+ super.makeText( s );
+ }
+
+ override def makeComment(s: String): Seq[Comment] = {
+ if(logComment)
+ log("[makeComment:\""+s+"\"]");
+ super.makeComment( s );
+ }
+
+ override def makeProcInstr(t: String, s: String): Seq[ProcInstr] = {
+ if(logProcInstr)
+ log("[makeProcInstr:\""+t+" "+ s+"\"]");
+ super.makeProcInstr(t,s);
+ }
+
+}
diff --git a/sources/scala/xml/factory/NodeFactory.scala b/sources/scala/xml/factory/NodeFactory.scala
new file mode 100644
index 0000000000..ed9caa1f42
--- /dev/null
+++ b/sources/scala/xml/factory/NodeFactory.scala
@@ -0,0 +1,77 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+** $Id $
+\* */
+
+package scala.xml.factory;
+
+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(pre: String, name: String, attrs: MetaData, scope: NamespaceBinding, children:Seq[Node]): A;
+
+ protected def construct(hash:Int, old:List[A], pre: String, name: String, attrSeq:MetaData, scope: NamespaceBinding, children:Seq[Node]): A = {
+ val el = create(pre, name, attrSeq, scope, children);
+ cache.update( hash, el::old );
+ el
+ }
+
+ /** faster equality, because */
+ def eqElements(ch1:Seq[Node], ch2:Seq[Node]): Boolean = {
+ (ch1.length == ch2.length) && {
+ val it1 = ch1.elements;
+ val it2 = ch2.elements;
+ var res = true;
+ while(res && it1.hasNext) {
+ res = it1.next.eq(it2.next);
+ }
+ res
+ }
+ }
+
+ def nodeEquals(n: Node, pre: String, name: String, attrSeq:MetaData, scope: NamespaceBinding, children:Seq[Node]) =
+ (n.prefix == pre)
+ &&(n.label == name)
+ &&(n.attributes == attrSeq)
+ // scope??
+ &&(eqElements(n.child,children));
+
+ def makeNode(pre: String, name: String, attrSeq:MetaData, scpe: NamespaceBinding, children:Seq[Node]): A = {
+ //Console.println("NodeFactory::makeNode("+pre+","+name+","+attrSeq+","+scpe+","+children+")");
+ val hash = Utility.hashCode( pre, name, attrSeq.hashCode(), scpe.hashCode(), children ) ;
+ cache.get( hash ) match {
+ case Some(list) => // find structurally equal
+ val it = list.elements;
+ val lookup = it.find { x => nodeEquals(x, pre, name, attrSeq, scpe, children) };
+ lookup match {
+ case Some(x) =>
+ //Console.println("[cache hit !]"+x);
+ x; // return cached elem
+ case _ => construct(hash, list, pre, name, attrSeq, scpe, children);
+ }
+ case _ => construct(hash, Nil, pre, name, attrSeq, scpe, children)
+ }
+ }
+
+ 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));
+
+}
diff --git a/sources/scala/xml/parsing/FactoryAdapter.scala b/sources/scala/xml/parsing/FactoryAdapter.scala
new file mode 100644
index 0000000000..d634a400d5
--- /dev/null
+++ b/sources/scala/xml/parsing/FactoryAdapter.scala
@@ -0,0 +1,344 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+** $Id$
+\* */
+package scala.xml.parsing ;
+
+import java.io._ ;
+import scala.collection.mutable.{HashMap,Stack};
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.InputSource;
+
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+
+
+/** SAX adapter class, for use with Java SAX parser. Keeps track of
+ * namespace bindings, without relying on namespace handling of the
+ * underlying SAX parser.
+ */
+abstract class FactoryAdapter extends DefaultHandler() {
+
+ val buffer = new StringBuffer();
+ val attribStack = new Stack[MetaData];
+ val hStack = new Stack[Node]; // [ element ] contains siblings
+ val tagStack = new Stack[String];
+ var scopeStack = new Stack[NamespaceBinding];
+
+ var curTag : String = null ;
+ var capture:boolean = false;
+
+ // abstract methods
+
+ /** Tests if an XML element contains text.
+ * @return true if element named <code>localName</code> contains text.
+ */
+ def nodeContainsText( localName:String ):boolean ; // abstract
+
+ /** creates an new non-text(tree) node.
+ * @param elemName
+ * @param attribs
+ * @param chIter
+ * @return a new XML element.
+ */
+ def createNode(pre: String, elemName: String, attribs: MetaData, scope: NamespaceBinding, chIter: List[Node] ):Node; //abstract
+
+ /** creates a Text node.
+ * @param text
+ * @return a new Text node.
+ */
+ def createText( text:String ):Text[String]; // abstract
+
+ //
+ // ContentHandler methods
+ //
+
+ val normalizeWhitespace = false;
+
+ /** Characters.
+ * @param ch
+ * @param offset
+ * @param length
+ */
+ override def characters(ch: Array[Char], offset: Int, length: Int): Unit = {
+
+ if (capture) {
+ if( normalizeWhitespace ) { // normalizing whitespace is not compliant, but useful */
+ var i:int = offset;
+ var ws:boolean = false;
+ while (i < offset + length) {
+ if ( Character.isWhitespace( ch(i) ) ) {
+ if (!ws) {
+ buffer.append(' ');
+ ws = true;
+ }
+ } else {
+ buffer.append(ch(i));
+ ws = false;
+ }
+ i = i+1;
+ }
+ } else { // compliant:report every character
+
+ buffer.append( ch, offset, length );
+
+ }
+ }
+ }
+
+ //var elemCount = 0; //STATISTICS
+
+ /* ContentHandler methods */
+
+ /* Start prefix mapping - use default impl.
+ def startPrefixMapping( prefix:String , uri:String ):Unit = {}
+ */
+
+
+
+ /* Start element. */
+ override def startElement(uri:String, _localName:String, qname:String, attributes:Attributes ):Unit = {
+ /*elemCount = elemCount + 1; STATISTICS */
+ captureText();
+ //Console.println("FactoryAdapter::startElement("+uri+","+_localName+","+qname+","+attributes+")");
+ tagStack.push(curTag);
+ curTag = qname; //localName ;
+
+ val colon = qname.indexOf(':');
+ val localName = if(-1 == colon) qname else qname.substring(colon+1,qname.length());
+
+ //Console.println("FactoryAdapter::startElement - localName ="+localName);
+
+ capture = nodeContainsText(localName) ;
+
+ hStack.push( null );
+ var m: MetaData = Null;
+
+ var scpe = scopeStack.top;
+ for( val i <- List.range( 0, attributes.getLength() )) {
+ //val attrType = attributes.getType(i); // unused for now
+ val qname = attributes.getQName(i);
+ val value = attributes.getValue(i);
+ val colon = qname.indexOf(':');
+ if(-1 != colon) { // prefixed attribute
+ val pre = qname.substring(0, colon);
+ val key = qname.substring(colon+1, qname.length());
+ if("xmlns" == pre)
+ scpe = value.length() match {
+ case 0 => new NamespaceBinding(key, null, scpe);
+ case _ => new NamespaceBinding(key, value, scpe);
+ }
+ else
+ m = new PrefixedAttribute(pre, key, value, m)
+ } else if("xmlns" == qname)
+ scpe = value.length() match {
+ case 0 => new NamespaceBinding(null, null, scpe);
+ case _ => new NamespaceBinding(null, value, scpe);
+ }
+ else
+ m = new UnprefixedAttribute(qname, value, m)
+ }
+ scopeStack.push(scpe);
+ attribStack.push( m );
+ {}
+ } // startElement(String,String,String,Attributes)
+
+
+ /** captures text, possibly normalizing whitespace
+ */
+ def captureText():Unit = {
+ if (capture == true) {
+ val text = buffer.toString();
+ if(( text.length() > 0 )&&( !( text.equals(" ")))) {
+ val _ = hStack.push( createText( text ) );
+ }
+ }
+ buffer.setLength(0);
+ }
+
+ /** End element.
+ * @param uri
+ * @param localName
+ * @param qname
+ * @throws org.xml.sax.SAXException if ..
+ */
+ override def endElement(uri:String , _localName:String , qname:String ):Unit = {
+ captureText();
+
+ val metaData = attribStack.pop;
+
+ // reverse order to get it right
+ var v:List[Node] = Nil;
+ var child:Node = hStack.pop;
+ while( child != null ) {
+ v = child::v;
+ child = hStack.pop;
+ }
+
+ val colon = qname.indexOf(':');
+ val localName = if(-1 == colon) qname else qname.substring(colon+1,qname.length());
+
+ val scp = scopeStack.pop;
+ // create element
+ rootElem = if(-1 == colon)
+ createNode( null, localName, metaData, scp, v );
+ else
+ createNode( qname.substring(0,colon), localName, metaData, scp, v );
+
+ hStack.push(rootElem);
+
+ // set
+ curTag = tagStack.pop;
+
+ if (curTag != null) // root level
+ capture = nodeContainsText(curTag);
+ else
+ capture = false;
+
+ } // endElement(String,String,String)
+
+ //
+ // ErrorHandler methods
+ //
+
+ /** Warning.*/
+ override def warning(ex:SAXParseException ):Unit = {
+ // ignore warning, crimson warns even for entity resolution!
+ //printError("Warning", ex);
+ }
+ /** Error. */
+ override def error(ex:SAXParseException ):Unit = {
+ printError("Error", ex);
+ }
+
+ /** Fatal error.*/
+ override def fatalError(ex:SAXParseException ):Unit = {
+ printError("Fatal Error", ex);
+ }
+
+ //
+ // Protected methods
+ //
+
+ /** Prints the error message */
+ protected def printError( errtype:String , ex:SAXParseException ):Unit = {
+
+ System.err.print("[");
+ System.err.print(errtype);
+ System.err.print("] ");
+
+ var systemId = ex.getSystemId();
+ if (systemId != null) {
+ val index = systemId.lastIndexOf('/');
+ if (index != -1)
+ systemId = systemId.substring(index + 1);
+ //System.err.print(systemId);
+ }
+
+ System.err.print(':');
+ System.err.print(ex.getLineNumber());
+ System.err.print(':');
+ System.err.print(ex.getColumnNumber());
+ System.err.print(": ");
+ System.err.print(ex.getMessage());
+ System.err.println();
+ System.err.flush();
+
+ }
+
+ var rootElem : Node = null:Node;
+
+ //FactoryAdapter
+ // MAIN
+ //
+
+ /** load XML document
+ * @param source
+ * @return a new XML document object
+ */
+ def loadXML( source:InputSource ):Node = {
+
+ // variables
+ var parser:SAXParser = null;
+
+ // create parser
+ try {
+ val f = SAXParserFactory.newInstance();
+ f.setNamespaceAware( false );
+ parser = f.newSAXParser();
+ } catch {
+ case ( e:Exception ) => {
+ System.err.println("error: Unable to instantiate parser");
+ System.exit(-1);
+ }
+ }
+
+ // parse file
+ try {
+ //System.err.println("[parsing \"" + source + "\"]");
+ scopeStack.push(TopScope);
+ parser.parse( source, this );
+ scopeStack.pop;
+ } catch {
+ case ( e:SAXParseException ) => {
+ // ignore
+ }
+ case ( e:Exception ) => {
+ System.err.println("error: Parse error occurred - " + e.getMessage());
+ if (e.isInstanceOf[ SAXException ]) {
+ (e.asInstanceOf[ SAXException ])
+ .getException()
+ .printStackTrace( System.err );
+ } else {
+ e.printStackTrace(System.err);
+ }
+ }
+ } // catch
+ //System.err.println("[FactoryAdapter: total #elements = "+elemCount+"]");
+ rootElem
+
+ } // loadXML
+
+
+
+ /** loads XML from given file */
+ def loadFile( file:File ):Node = loadXML( new InputSource(
+ new FileInputStream( file )
+ ));
+
+ /** loads XML from given file descriptor */
+ def loadFile( fileDesc:FileDescriptor ):Node = loadXML( new InputSource(
+ new FileInputStream( fileDesc )
+ ));
+
+ /** loads XML from given file */
+ def loadFile( fileName:String ):Node = loadXML( new InputSource(
+ new FileInputStream( fileName )
+ ));
+
+ /** loads XML from given InputStream */
+ def load( is:InputStream ):Node = loadXML( new InputSource( is ));
+
+ /** loads XML from given Reader */
+ def load( reader:Reader ):Node = loadXML( new InputSource( reader ));
+
+ /** loads XML from given sysID */
+ def load( sysID:String ):Node = loadXML( new InputSource( sysID ));
+
+}
diff --git a/sources/scala/xml/parsing/NoBindingFactoryAdapter.scala b/sources/scala/xml/parsing/NoBindingFactoryAdapter.scala
new file mode 100644
index 0000000000..d2400e33d3
--- /dev/null
+++ b/sources/scala/xml/parsing/NoBindingFactoryAdapter.scala
@@ -0,0 +1,53 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+** $Id$
+\* */
+package scala.xml.parsing;
+
+import scala.xml.factory.NodeFactory ;
+import org.xml.sax.InputSource;
+
+/** nobinding adaptor providing callbacks to parser to create elements.
+* implements hash-consing
+*/
+class NoBindingFactoryAdapter extends FactoryAdapter with NodeFactory[Elem] {
+
+ // -- FactoryAdapter methods
+
+ /** returns true. Every XML node may contain text that the application needs
+ **/
+ def nodeContainsText( label:java.lang.String ):boolean = true;
+
+
+ // methods for NodeFactory[Elem]
+
+ /** constructs an instance of scala.xml.Elem */
+ protected def create(pre: String, label: String, attrs: MetaData, scpe: NamespaceBinding, children:Seq[Node]): Elem = {
+ Elem( pre, label, attrs, scpe, children:_* );
+ }
+
+ // -- methods for FactoryAdapter
+
+ /** creates a node. never creates the same node twice, using hash-consing
+ */
+ def createNode(pre:String, label: String, attrs: MetaData, scpe: NamespaceBinding, children: List[Node] ): Elem = {
+ //Console.println("NoBindingFactoryAdapter::createNode("+pre+","+label+","+attrs+","+scpe+","+children+")");
+ Elem( pre, label, attrs, scpe, children:_* );
+ //makeNode(pre, label, attrs, scpe, children);
+ }
+
+ /** creates a text node
+ */
+ def createText( text:String ) =
+ Text( text );
+
+ /** loads an XML document, returning a Symbol node.
+ */
+ override def loadXML( source:InputSource ):Elem =
+ super.loadXML( source ).asInstanceOf[ Elem ];
+
+}