summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sources/scala/tools/dtd2scala/template/ObjectTemplate.scala.xml2
-rw-r--r--sources/scala/xml/AttributeSeq.scala34
-rw-r--r--sources/scala/xml/BindingFactoryAdapter.scala20
-rw-r--r--sources/scala/xml/Node.scala8
-rw-r--r--sources/scala/xml/NodeBuffer.scala9
-rw-r--r--sources/scala/xml/NodeFactory.scala67
-rw-r--r--sources/scala/xml/UName.scala4
-rw-r--r--sources/scala/xml/Utility.scala5
-rw-r--r--sources/scala/xml/nobinding/NoBindingFactoryAdapter.scala14
-rw-r--r--test/files/xml/lnk.xml2
10 files changed, 154 insertions, 11 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
diff --git a/test/files/xml/lnk.xml b/test/files/xml/lnk.xml
index c4605be246..f166079b42 100644
--- a/test/files/xml/lnk.xml
+++ b/test/files/xml/lnk.xml
@@ -2,7 +2,7 @@
<!DOCTYPE lnkDB SYSTEM "lnk.dtd">
<!-- try this DOCTYPE lnkDB SYSTEM "lnkDB.dtd" [ <!ELEMENT newEl (link*)> ] -->
-<lnkDB>
+<lnkDB xmlns="http://scala.epfl.ch/testSuite/links">
<linkgroup>
<groupname>LDAP Links</groupname>