summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-06-03 16:41:02 +0000
committerPaul Phillips <paulp@improving.org>2009-06-03 16:41:02 +0000
commit56b22f27d03cd964d2bbb9f72e0c2b5bc9d8f4cf (patch)
treef37a7fb93273414f3c6a25d98e43c25b5a187d0c /src
parente46e603f658ee9cbec4d762928b6645fd7f6b8cd (diff)
downloadscala-56b22f27d03cd964d2bbb9f72e0c2b5bc9d8f4cf.tar.gz
scala-56b22f27d03cd964d2bbb9f72e0c2b5bc9d8f4cf.tar.bz2
scala-56b22f27d03cd964d2bbb9f72e0c2b5bc9d8f4cf.zip
Abstracted XML loading interface into xml.facto...
Abstracted XML loading interface into xml.factory.XMLLoader. Now scala.xml.XML uses a default implementation of XMLLoader, and XML.withSAXParser(parser) creates a new one which will use the supplied parser. Implements feature #1436.
Diffstat (limited to 'src')
-rw-r--r--src/library/scala/xml/XML.scala62
-rw-r--r--src/library/scala/xml/factory/NodeFactory.scala88
-rw-r--r--src/library/scala/xml/factory/XMLLoader.scala60
-rw-r--r--src/library/scala/xml/parsing/FactoryAdapter.scala54
-rw-r--r--src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala60
5 files changed, 138 insertions, 186 deletions
diff --git a/src/library/scala/xml/XML.scala b/src/library/scala/xml/XML.scala
index 1c41af5117..13b62539f3 100644
--- a/src/library/scala/xml/XML.scala
+++ b/src/library/scala/xml/XML.scala
@@ -11,14 +11,29 @@
package scala.xml
-
import Predef._
import scala.xml.parsing.NoBindingFactoryAdapter
+import scala.xml.factory.XMLLoader
import org.xml.sax.InputSource
+import javax.xml.parsers.{ SAXParser, SAXParserFactory }
import java.io.{File, FileDescriptor, FileInputStream, FileOutputStream}
import java.io.{InputStream, Reader, StringReader, Writer}
+import java.nio.channels.Channels
import scala.util.control.Exception.ultimately
+object Source
+{
+ def fromFile(file: File) = new InputSource(new FileInputStream(file))
+ def fromFile(fd: FileDescriptor) = new InputSource(new FileInputStream(fd))
+ def fromFile(name: String) = new InputSource(new FileInputStream(name))
+
+ def fromInputStream(is: InputStream) = new InputSource(is)
+ def fromReader(reader: Reader) = new InputSource(reader)
+ def fromSysId(sysID: String) = new InputSource(sysID)
+ def fromString(string: String) = fromReader(new StringReader(string))
+}
+import Source._
+
/** The object <code>XML</code> provides constants, and functions to load
* and save XML elements. Use this when data binding is not desired, i.e.
* when XML is handled using <code>Symbol</code> nodes.
@@ -26,7 +41,7 @@ import scala.util.control.Exception.ultimately
* @author Burak Emir
* @version 1.0, 25/04/2005
*/
-object XML
+object XML extends XMLLoader[Elem]
{
val xml = "xml"
val xmlns = "xmlns"
@@ -36,43 +51,9 @@ object XML
val lang = "lang"
val encoding = "ISO-8859-1"
- // functions for generic xml loading, saving
- private def mkAdapter(is: InputSource): Elem = new NoBindingFactoryAdapter().loadXML(is)
- private def mkAdapter(fis: FileInputStream): Elem = mkAdapter(new InputSource(fis))
-
- /** loads XML from given file, using XML parser in JDK. */
- final def loadFile(file: File): Elem =
- mkAdapter(new FileInputStream(file))
-
- /** loads XML from given file descriptor, using XML parser in JDK. */
- final def loadFile(fileDesc: FileDescriptor): Elem =
- mkAdapter(new FileInputStream(fileDesc))
-
- /** loads XML from given file, using XML parser in JDK. */
- final def loadFile(fileName: String): Elem =
- mkAdapter(new FileInputStream(fileName))
-
- /** loads XML from given InputStream, using XML parser in JDK. */
- final def load(is: InputStream): Elem =
- mkAdapter(new InputSource(is))
-
- /** loads XML from given Reader, using XML parser in JDK. */
- final def load(reader: Reader): Elem =
- mkAdapter(new InputSource(reader))
-
- /** loads XML from given sysID, using XML parser in JDK. */
- final def load(sysID: String): Elem =
- mkAdapter(new InputSource(sysID))
-
- /** loads XML from a given input source, using XML parser in JDK.
- *
- * @param source ...
- * @return ...
- */
- final def load(source: InputSource): Elem = mkAdapter(source)
-
- /** loads XML from a string, using XML parser in JDK. */
- final def loadString(string: String): Elem = load(new StringReader(string))
+ /** Returns an XMLLoader whose load* methods will use the supplied SAXParser. */
+ def withSAXParser(p: SAXParser): XMLLoader[Elem] =
+ new XMLLoader[Elem] { override val parser: SAXParser = p }
@deprecated("Use save() instead")
final def saveFull(filename: String, node: Node, xmlDecl: Boolean, doctype: dtd.DocType): Unit =
@@ -99,9 +80,6 @@ object XML
doctype: dtd.DocType
): Unit =
{
- // using NIO classes of JDK 1.4
- import java.io._
- import java.nio.channels._
val fos = new FileOutputStream(filename)
val w = Channels.newWriter(fos.getChannel(), enc)
diff --git a/src/library/scala/xml/factory/NodeFactory.scala b/src/library/scala/xml/factory/NodeFactory.scala
index 4d5743548d..718240760d 100644
--- a/src/library/scala/xml/factory/NodeFactory.scala
+++ b/src/library/scala/xml/factory/NodeFactory.scala
@@ -8,70 +8,56 @@
// $Id$
+package scala.xml.factory
-package scala.xml.factory;
+import parsing.{ FactoryAdapter, NoBindingFactoryAdapter }
+import org.xml.sax.InputSource
+import java.io.{ InputStream, Reader, StringReader, File, FileDescriptor, FileInputStream }
+import javax.xml.parsers.{ SAXParser, SAXParserFactory }
-
-trait NodeFactory[A <: Node] {
-
- val ignoreComments = false;
- val ignoreProcInstr = false;
+trait NodeFactory[A <: Node]
+{
+ val ignoreComments = false
+ val ignoreProcInstr = false
/* default behaviour is to use hash-consing */
- val cache = new collection.mutable.HashMap[Int, List[A]]();
+ val cache = new collection.mutable.HashMap[Int, List[A]]
- protected def create(pre: String, name: String, attrs: MetaData, scope: NamespaceBinding, children:Seq[Node]): 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 );
+ 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.iterator;
- val it2 = ch2.iterator;
- 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.iterator;
- 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);
+ def eqElements(ch1: Seq[Node], ch2: Seq[Node]): Boolean =
+ ch1.view.zipAll(ch2.view, null, null) forall { case (x,y) => x eq y }
+
+ 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, scope: NamespaceBinding, children: Seq[Node]): A = {
+ val hash = Utility.hashCode( pre, name, attrSeq.hashCode(), scope.hashCode(), children)
+ def cons(old: List[A]) = construct(hash, old, pre, name, attrSeq, scope, children)
+
+ (cache get hash) match {
+ case Some(list) => // find structurally equal
+ list.find(nodeEquals(_, pre, name, attrSeq, scope, children)) match {
+ case Some(x) => x
+ case _ => cons(list)
}
- case _ => construct(hash, Nil, pre, name, attrSeq, scpe, children)
+ case None => cons(Nil)
}
}
- def makeText(s: String) =
- Text( s );
-
- def makeComment(s: String): Seq[Comment] =
- if(ignoreComments) Nil else List(Comment( s ));
-
+ 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));
-
+ if (ignoreProcInstr) Nil else List(ProcInstr(t, s))
}
diff --git a/src/library/scala/xml/factory/XMLLoader.scala b/src/library/scala/xml/factory/XMLLoader.scala
new file mode 100644
index 0000000000..8526d6d623
--- /dev/null
+++ b/src/library/scala/xml/factory/XMLLoader.scala
@@ -0,0 +1,60 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id$
+
+package scala.xml.factory
+
+import parsing.{ FactoryAdapter, NoBindingFactoryAdapter }
+import org.xml.sax.InputSource
+import java.io.{ InputStream, Reader, StringReader, File, FileDescriptor, FileInputStream }
+import javax.xml.parsers.{ SAXParser, SAXParserFactory }
+
+/** Presents collection of XML loading methods which use the parser
+ * created by "def parser".
+ */
+trait XMLLoader[T <: Node]
+{
+ import scala.xml.Source._
+ def adapter: FactoryAdapter = new NoBindingFactoryAdapter()
+
+ /* Override this to use a different SAXParser. */
+ def parser: SAXParser = {
+ val f = SAXParserFactory.newInstance()
+ f.setNamespaceAware(false)
+ f.newSAXParser()
+ }
+
+ /** Loads XML from the given InputSource, using the supplied parser.
+ * The methods available in scala.xml.XML use the XML parser in the JDK.
+ */
+ def loadXML(source: InputSource, parser: SAXParser): T = {
+ val newAdapter = adapter
+ import newAdapter._
+
+ scopeStack push TopScope
+ parser.parse(source, newAdapter)
+ scopeStack.pop
+
+ rootElem.asInstanceOf[T]
+ }
+
+ /** Loads XML from the given file, file descriptor, or filename. */
+ def loadFile(file: File): T = loadXML(fromFile(file), parser)
+ def loadFile(fd: FileDescriptor): T = loadXML(fromFile(fd), parser)
+ def loadFile(name: String): T = loadXML(fromFile(name), parser)
+
+ /** loads XML from given InputStream, Reader, sysID, or InputSource. */
+ def load(is: InputStream): T = loadXML(fromInputStream(is), parser)
+ def load(reader: Reader): T = loadXML(fromReader(reader), parser)
+ def load(sysID: String): T = loadXML(fromSysId(sysID), parser)
+ def load(source: InputSource): T = loadXML(source, parser)
+
+ /** Loads XML from the given String. */
+ def loadString(string: String): T = loadXML(fromString(string), parser)
+} \ No newline at end of file
diff --git a/src/library/scala/xml/parsing/FactoryAdapter.scala b/src/library/scala/xml/parsing/FactoryAdapter.scala
index 4c09988151..f212761db6 100644
--- a/src/library/scala/xml/parsing/FactoryAdapter.scala
+++ b/src/library/scala/xml/parsing/FactoryAdapter.scala
@@ -41,7 +41,9 @@ trait ConsoleErrorHandler extends DefaultHandler
* namespace bindings, without relying on namespace handling of the
* underlying SAX parser.
*/
-abstract class FactoryAdapter extends DefaultHandler() {
+abstract class FactoryAdapter extends DefaultHandler with factory.XMLLoader[Node]
+{
+ var rootElem: Node = null
val buffer = new StringBuilder()
val attribStack = new Stack[MetaData]
@@ -218,54 +220,4 @@ abstract class FactoryAdapter extends DefaultHandler() {
for (pi <- createProcInstr(target, data))
hStack.push(pi)
}
-
- var rootElem: Node = null
-
- //FactoryAdapter
- // MAIN
- //
-
- private def mkParser(): SAXParser = {
- val f = SAXParserFactory.newInstance()
- f.setNamespaceAware(false)
- f.newSAXParser()
- }
-
- /** load XML document
- * @param source
- * @return a new XML document object
- */
- def loadXML(source: InputSource): Node = {
- val parser: SAXParser = mkParser
- scopeStack.push(TopScope)
- parser.parse(source, this)
- scopeStack.pop
-
- 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/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala b/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala
index 66190d088a..ee0b8a9ec0 100644
--- a/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala
+++ b/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala
@@ -8,55 +8,31 @@
// $Id$
+package scala.xml.parsing
-package scala.xml.parsing;
-
-
-import scala.xml.factory.NodeFactory;
-import org.xml.sax.InputSource;
+import scala.xml.factory.NodeFactory
+import org.xml.sax.InputSource
+import javax.xml.parsers.{ SAXParser, SAXParserFactory }
/** 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);
- }
+class NoBindingFactoryAdapter extends FactoryAdapter with NodeFactory[Elem]
+{
+ /** True. Every XML node may contain text that the application needs */
+ def nodeContainsText(label: String) = true
- /** creates a text node
- */
- def createText( text:String ) =
- Text( text );
+ /** From NodeFactory. Constructs an instance of scala.xml.Elem */
+ protected def create(pre: String, label: String, attrs: MetaData, scope: NamespaceBinding, children: Seq[Node]): Elem =
+ Elem(pre, label, attrs, scope, children: _*)
- /** create a processing instruction
- */
- def createProcInstr(target: String, data: String) =
- makeProcInstr(target, data)
+ /** From FactoryAdapter. Creates a node. never creates the same node twice, using hash-consing. */
+ def createNode(pre: String, label: String, attrs: MetaData, scope: NamespaceBinding, children: List[Node]): Elem =
+ Elem(pre, label, attrs, scope, children: _*)
- /** loads an XML document, returning a Symbol node.
- */
- override def loadXML( source:InputSource ):Elem =
- super.loadXML( source ).asInstanceOf[ Elem ];
+ /** Creates a text node. */
+ def createText(text: String) = Text(text)
+ /** Creates a processing instruction. */
+ def createProcInstr(target: String, data: String) = makeProcInstr(target, data)
}