diff options
51 files changed, 434 insertions, 497 deletions
diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 9a61f38be2..ca8549bffa 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -15,7 +15,7 @@ import scala.reflect.ClassManifest import scala.collection.{ Seq, IndexedSeq } import scala.collection.mutable.WrappedArray import scala.collection.immutable.{ List, Stream, Nil, :: } -import scala.xml.Node +import scala.xml.{ Node, MetaData } import scala.util.control.ControlException /* The object <code>ScalaRunTime</code> provides ... @@ -192,12 +192,14 @@ object ScalaRunTime { case null => "null" // Node extends NodeSeq extends Seq[Node] strikes again case x: Node => x toString + // Not to mention MetaData extends Iterable[MetaData] + case x: MetaData => x toString case x: AnyRef if isArray(x) => WrappedArray make x map inner mkString ("Array(", ", ", ")") case x: Traversable[_] if !x.hasDefiniteSize => x.toString case x: Traversable[_] => // Some subclasses of AbstractFile implement Iterable, then throw an // exception if you call iterator. What a world. - // And they can't be infinite either. + // And they can't be infinite either. if (x.getClass.getName startsWith "scala.tools.nsc.io") x.toString else (x map inner) mkString (x.stringPrefix + "(", ", ", ")") case x => x toString diff --git a/src/library/scala/testing/SUnit.scala b/src/library/scala/testing/SUnit.scala index cf43bd1b06..d5d845cb98 100644 --- a/src/library/scala/testing/SUnit.scala +++ b/src/library/scala/testing/SUnit.scala @@ -12,6 +12,7 @@ package scala.testing import scala.collection.mutable.ArrayBuffer +import xml.{ Node, NodeSeq } /** * <p> @@ -237,6 +238,25 @@ object SUnit { assertTrue("(no message)", actual) } + /** Temporary patchwork trying to nurse xml forward. */ + def assertEqualsXML(msg: String, expected: NodeSeq, actual: NodeSeq) { + if (!expected.xml_==(actual)) + fail(msg, expected, actual) + } + def assertEqualsXML(msg: String, expected: Seq[Node], actual: Seq[Node]) { + assertEqualsXML(msg, expected: NodeSeq, actual: NodeSeq) + } + + def assertEqualsXML(expected: NodeSeq, actual: NodeSeq) { + assertEqualsXML("(no message)", expected, actual) + } + + def assertSameElementsXML(actual: Seq[Node], expected: Seq[Node]) { + val res = (actual: NodeSeq) xml_sameElements expected + + assert(res, "\nassertSameElementsXML:\n actual = %s\n expected = %s".format(actual, expected)) + } + /** throws <code>AssertFailed</code> with given message <code>msg</code>. */ def fail(msg: String) { diff --git a/src/library/scala/xml/Atom.scala b/src/library/scala/xml/Atom.scala index 129a0803d2..7c66995573 100644 --- a/src/library/scala/xml/Atom.scala +++ b/src/library/scala/xml/Atom.scala @@ -8,9 +8,7 @@ // $Id$ - package scala.xml -import collection.mutable.StringBuilder /** The class <code>Atom</code> provides an XML node for text (PCDATA). * It is used in both non-bound and bound XML representations. @@ -24,17 +22,21 @@ class Atom[+A](val data: A) extends SpecialNode if (data == null) throw new IllegalArgumentException("cannot construct Atom(null)") + override def basisForHashCode: Seq[Any] = Seq(data) + override def strict_==(other: Equality) = other match { + case x: Atom[_] => data == x.data + case _ => false + } + override def canEqual(other: Any) = other match { + case _: Atom[_] => true + case _ => false + } + final override def doCollectNamespaces = false final override def doTransform = false def label = "#PCDATA" - override def equals(x: Any) = x match { - case s:Atom[_] => data == s.data - case _ => false - } - override def hashCode() = data.hashCode() - /** Returns text, with some characters escaped according to the XML * specification. * diff --git a/src/library/scala/xml/Attribute.scala b/src/library/scala/xml/Attribute.scala index 8ff9fb2ed7..3259526d98 100644 --- a/src/library/scala/xml/Attribute.scala +++ b/src/library/scala/xml/Attribute.scala @@ -10,9 +10,6 @@ package scala.xml -import collection.Seq -import collection.mutable.StringBuilder - /** Attribute defines the interface shared by both * PrefixedAttribute and UnprefixedAttribute */ @@ -45,6 +42,7 @@ object Attribute { abstract trait Attribute extends MetaData { + def pre: String // will be null if unprefixed val key: String val value: Seq[Node] val next: MetaData @@ -52,13 +50,43 @@ abstract trait Attribute extends MetaData def apply(key: String): Seq[Node] def apply(namespace: String, scope: NamespaceBinding, key: String): Seq[Node] def copy(next: MetaData): Attribute - def remove(key: String): MetaData - def remove(namespace: String, scope: NamespaceBinding, key: String): MetaData - def isPrefixed: Boolean + def remove(key: String) = + if (!isPrefixed && this.key == key) next + else copy(next remove key) + + def remove(namespace: String, scope: NamespaceBinding, key: String) = + if (isPrefixed && this.key == key && (scope getURI pre) == namespace) next + else next.remove(namespace, scope, key) + + def isPrefixed: Boolean = pre != null def getNamespace(owner: Node): String - def wellformed(scope: NamespaceBinding): Boolean + def wellformed(scope: NamespaceBinding): Boolean = { + val arg = if (isPrefixed) scope getURI pre else null + (next(arg, scope, key) == null) && (next wellformed scope) + } - def equals1(m: MetaData): Boolean - def toString1(sb: StringBuilder): Unit + override def canEqual(other: Any) = other match { + case _: Attribute => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case x: Attribute => (pre == x.pre) && (key == x.key) && (value sameElements x.value) + case _ => false + } + override def basisForHashCode = List(pre, key, value) + + /** Appends string representation of only this attribute to stringbuffer. + */ + def toString1(sb: StringBuilder) { + if (value == null) + return + if (isPrefixed) + sb append pre append ':' + + sb append key append '=' + val sb2 = new StringBuilder() + Utility.sequenceToXML(value, TopScope, sb2, true) + Utility.appendQuoted(sb2.toString(), sb) + } } diff --git a/src/library/scala/xml/Comment.scala b/src/library/scala/xml/Comment.scala index 4e8cff8d75..9608748601 100644 --- a/src/library/scala/xml/Comment.scala +++ b/src/library/scala/xml/Comment.scala @@ -10,7 +10,7 @@ package scala.xml -import collection.mutable.StringBuilder + /** The class <code>Comment</code> implements an XML node for comments. * diff --git a/src/library/scala/xml/Document.scala b/src/library/scala/xml/Document.scala index 3ac50b80b7..6c73252a37 100644 --- a/src/library/scala/xml/Document.scala +++ b/src/library/scala/xml/Document.scala @@ -87,4 +87,8 @@ class Document extends NodeSeq with pull.XMLEvent { def theSeq: Seq[Node] = this.docElem + override def canEqual(other: Any) = other match { + case _: Document => true + case _ => false + } } diff --git a/src/library/scala/xml/Elem.scala b/src/library/scala/xml/Elem.scala index 18b513527c..9c58177417 100644 --- a/src/library/scala/xml/Elem.scala +++ b/src/library/scala/xml/Elem.scala @@ -8,11 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq - /** This singleton object contains the apply and unapplySeq methods for convenient construction and * deconstruction. It is possible to deconstruct any Node instance (that is not a SpecialNode or * a Group) using the syntax @@ -26,8 +23,10 @@ object Elem def apply(prefix: String,label: String, attributes: MetaData, scope: NamespaceBinding, child: Node*) = new Elem(prefix,label,attributes,scope,child:_*) - def unapplySeq(n:Node) = if (n.isInstanceOf[SpecialNode] || n.isInstanceOf[Group]) None else - Some((n.prefix, n.label, n.attributes, n.scope, n.child)) + def unapplySeq(n: Node) = n match { + case _: SpecialNode | _: Group => None + case _ => Some((n.prefix, n.label, n.attributes, n.scope, n.child)) + } } /** The case class <code>Elem</code> extends the <code>Node</code> class, @@ -54,18 +53,17 @@ extends Node final override def doCollectNamespaces = true final override def doTransform = true - if ((null != prefix) && 0 == prefix.length()) + if (prefix == "") throw new IllegalArgumentException("prefix of zero length, use null instead") - if (null == scope) - throw new IllegalArgumentException("scope is null, try xml.TopScope for empty scope") + if (scope == null) + throw new IllegalArgumentException("scope is null, use xml.TopScope for empty scope") //@todo: copy the children, // setting namespace scope if necessary // cleaning adjacent text nodes if necessary - override def hashCode(): Int = - Utility.hashCode(prefix, label, attributes.hashCode(), scope.hashCode(), child) + override def basisForHashCode: Seq[Any] = prefix :: label :: attributes :: child.toList /** Returns a new element with updated attributes, resolving namespace uris from this element's scope. * See MetaData.update for details. diff --git a/src/library/scala/xml/EntityRef.scala b/src/library/scala/xml/EntityRef.scala index 0806b8fa68..fbc1f351cf 100644 --- a/src/library/scala/xml/EntityRef.scala +++ b/src/library/scala/xml/EntityRef.scala @@ -10,7 +10,7 @@ package scala.xml -import collection.mutable.StringBuilder + /** The class <code>EntityRef</code> implements an XML node for entity diff --git a/src/library/scala/xml/Equality.scala b/src/library/scala/xml/Equality.scala new file mode 100644 index 0000000000..d09ae10b2d --- /dev/null +++ b/src/library/scala/xml/Equality.scala @@ -0,0 +1,115 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.xml + +/** In an attempt to contain the damage being inflicted on + * consistency by the ad hoc equals methods spread around + * xml, the logic is centralized and all the xml classes + * go through the xml.Equality trait. There are two forms + * of xml comparison. + * + * 1) def strict_==(other: xml.Equality) + * + * This one tries to honor the little things like symmetry + * and hashCode contracts. The equals method routes all + * comparisons through this. + * + * 2) xml_==(other: Any) + * + * This one picks up where strict_== leaves off. It might + * declare any two things equal. + * + * As things stood, the logic not only made a mockery of + * the collections equals contract, but also laid waste to + * that of case classes. + * + * Among the obstacles to sanity are/were: + * + * Node extends NodeSeq extends Seq[Node] + * MetaData extends Iterable[MetaData] + * The hacky "Group" xml node which throws exceptions + * with wild abandon, so don't get too close + * Rampant asymmetry and impossible hashCodes + * Most classes claiming to be equal to "String" if + * some specific stringification of it was the same. + * String was never going to return the favor. + */ + +object Equality { + def asRef(x: Any): AnyRef = x.asInstanceOf[AnyRef] + + /** Note - these functions assume strict equality has already failed. + */ + def compareBlithely(x1: AnyRef, x2: String): Boolean = x1 match { + case x: Atom[_] => x.data == x2 + case x: NodeSeq => x.text == x2 + case _ => false + } + def compareBlithely(x1: AnyRef, x2: Node): Boolean = x1 match { + case x: NodeSeq if x.length == 1 => x2 == x(0) + case _ => false + } + def compareBlithely(x1: AnyRef, x2: AnyRef): Boolean = { + if (x1 == null || x2 == null) + return (x1 eq x2) + + x2 match { + case s: String => compareBlithely(x1, s) + case n: Node => compareBlithely(x1, n) + case _ => false + } + } +} +import Equality._ + +private[xml] +trait Equality extends scala.Equals { + def basisForHashCode: Seq[Any] + def strict_==(other: Equality): Boolean + def strict_!=(other: Equality) = !strict_==(other) + + private def hashOf(x: Any) = if (x == null) 1 else x.hashCode() + + /** We insist we're only equal to other xml.Equality implementors, + * which heads off a lot of inconsistency up front. + */ + override def canEqual(other: Any): Boolean = other match { + case x: Equality => true + case _ => false + } + + /** It's be nice to make these final, but there are probably + * people out there subclassing the XML types, especially when + * it comes to equals. However WE at least can pretend they + * are final since clearly individual classes cannot be trusted + * to maintain a semblance of order. + */ + override def hashCode() = basisForHashCode match { + case Nil => 0 + case x :: xs => hashOf(x) * 41 + (xs map hashOf).foldLeft(0)(_ * 7 + _) + } + override def equals(other: Any) = doComparison(other, false) + final def xml_==(other: Any) = doComparison(other, true) + final def xml_!=(other: Any) = !xml_==(other) + + /** The "blithe" parameter expresses the caller's unconcerned attitude + * regarding the usual constraints on equals. The method is thereby + * given carte blanche to declare any two things equal. + */ + private def doComparison(other: Any, blithe: Boolean) = { + val strictlyEqual = other match { + case x: AnyRef if this eq x => true + case x: Equality => (x canEqual this) && (this strict_== x) + case _ => false + } + + strictlyEqual || (blithe && compareBlithely(this, asRef(other))) + } +} + diff --git a/src/library/scala/xml/Group.scala b/src/library/scala/xml/Group.scala index 91ddba6ce6..8b714d2813 100644 --- a/src/library/scala/xml/Group.scala +++ b/src/library/scala/xml/Group.scala @@ -8,9 +8,7 @@ // $Id$ - package scala.xml -import collection.Seq /** A hack to group XML nodes in one node for output. * @@ -18,49 +16,27 @@ import collection.Seq * @version 1.0 */ @serializable -case class Group(val nodes: Seq[Node]) extends Node { - // final override def doTransform = false +final case class Group(val nodes: Seq[Node]) extends Node { override def theSeq = nodes - /** XXX this is ridiculous, we can't do equality like this. */ - override def equals(x: Any) = x match { - case z:Group => (length == z.length) && sameElements(z) - case z:Node => (length == 1) && z == apply(0) - case z:Seq[_] => sameElements(z) - case z:String => text == z - case _ => false + override def canEqual(other: Any) = other match { + case x: Group => true + case _ => false } - /* As if there were a hashCode which could back up the above implementation! */ - override def hashCode = nodes.hashCode - - /** - * @throws Predef.UnsupportedOperationException (always) - */ - final def label = - throw new UnsupportedOperationException("class Group does not support method 'label'") - - /** - * @throws Predef.UnsupportedOperationException (always) - */ - final override def attributes = - throw new UnsupportedOperationException("class Group does not support method 'attributes'") - - /** - * @throws Predef.UnsupportedOperationException (always) - */ - final override def namespace = - throw new UnsupportedOperationException("class Group does not support method 'namespace'") + override def strict_==(other: Equality) = other match { + case Group(xs) => nodes sameElements xs + case _ => false + } + override def basisForHashCode = nodes - /** - * @throws Predef.UnsupportedOperationException (always) + /** Since Group is very much a hack it throws an exception if you + * try to do anything with it. */ - final override def child = - throw new UnsupportedOperationException("class Group does not support method 'child'") + private def fail(msg: String) = throw new UnsupportedOperationException("class Group does not support method '%s'" format msg) - /** - * @throws Predef.UnsupportedOperationException (always) - */ - def buildString(sb: StringBuilder) = - throw new UnsupportedOperationException( - "class Group does not support method toString(StringBuilder)") + def label = fail("label") + override def attributes = fail("attributes") + override def namespace = fail("namespace") + override def child = fail("child") + def buildString(sb: StringBuilder) = fail("toString(StringBuilder)") } diff --git a/src/library/scala/xml/MetaData.scala b/src/library/scala/xml/MetaData.scala index 01b1cbc1d9..744b662fb8 100644 --- a/src/library/scala/xml/MetaData.scala +++ b/src/library/scala/xml/MetaData.scala @@ -8,14 +8,10 @@ // $Id$ - package scala.xml import Utility.sbToString import annotation.tailrec -import collection.immutable.List -import collection.{Seq, Iterator, Iterable} -import collection.mutable.StringBuilder /** @@ -77,7 +73,7 @@ object MetaData { * @author Burak Emir <bqe@google.com> */ @serializable -abstract class MetaData extends Iterable[MetaData] +abstract class MetaData extends Iterable[MetaData] with Equality { /** Updates this MetaData with the MetaData given as argument. All attributes that occur in updates * are part of the resulting MetaData. If an attribute occurs in both this instance and @@ -118,13 +114,6 @@ abstract class MetaData extends Iterable[MetaData] */ def apply(namespace_uri:String, scp:NamespaceBinding, k:String): Seq[Node] - /** - * @param m ... - * @return <code>true</code> iff ... - */ - def containedIn1(m: MetaData): Boolean = - m != null && (m.equals1(this) || containedIn1(m.next)) - /** returns a copy of this MetaData item with next field set to argument. * * @param next ... @@ -143,22 +132,20 @@ abstract class MetaData extends Iterable[MetaData] def isPrefixed: Boolean - /** deep equals method - XXX */ - override def equals(that: Any) = that match { - case m: MetaData => - (this.length == m.length) && - (this.hashCode == m.hashCode) && - (this forall (_ containedIn1 m)) + override def canEqual(other: Any) = other match { + case _: MetaData => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case m: MetaData => this.toSet == m.toSet case _ => false } + def basisForHashCode: Seq[Any] = List(this.toSet) /** Returns an iterator on attributes */ - def iterator: Iterator[MetaData] = Iterator.iterate(this)(_.next) takeWhile (_ != Null) + def iterator: Iterator[MetaData] = Iterator.single(this) ++ next.iterator override def size: Int = 1 + iterator.length - /** shallow equals method */ - def equals1(that: MetaData): Boolean - /** filters this sequence of meta data */ override def filter(f: MetaData => Boolean): MetaData = if (f(this)) copy(next filter f) @@ -170,8 +157,18 @@ abstract class MetaData extends Iterable[MetaData] /** returns value of this MetaData item */ def value: Seq[Node] - /** maps this sequence of meta data */ - def map(f: MetaData => Text): List[Text] = (iterator map f).toList + /** Returns a String containing "prefix:key" if the first key is + * prefixed, and "key" otherwise. + */ + def prefixedKey = this match { + case x: Attribute if x.isPrefixed => x.pre + ":" + key + case _ => key + } + + /** Returns a Map containing the attributes stored as key/value pairs. + */ + def asAttrMap: Map[String, String] = + iterator map (x => (x.prefixedKey, x.value.text)) toMap /** returns Null or the next MetaData item */ def next: MetaData @@ -198,8 +195,6 @@ abstract class MetaData extends Iterable[MetaData] final def get(uri: String, scope: NamespaceBinding, key: String): Option[Seq[Node]] = Option(apply(uri, scope, key)) - override def hashCode(): Int - def toString1(): String = sbToString(toString1) // appends string representations of single attribute to StringBuilder diff --git a/src/library/scala/xml/NamespaceBinding.scala b/src/library/scala/xml/NamespaceBinding.scala index 7381f0129b..47ca8fed87 100644 --- a/src/library/scala/xml/NamespaceBinding.scala +++ b/src/library/scala/xml/NamespaceBinding.scala @@ -12,7 +12,7 @@ package scala.xml import Utility.sbToString -import collection.mutable.StringBuilder + /** The class <code>NamespaceBinding</code> represents namespace bindings * and scopes. The binding for the default namespace is treated as a null @@ -23,7 +23,7 @@ import collection.mutable.StringBuilder * @version 1.0 */ @SerialVersionUID(0 - 2518644165573446725L) -case class NamespaceBinding(prefix: String, uri: String, parent: NamespaceBinding) extends AnyRef +case class NamespaceBinding(prefix: String, uri: String, parent: NamespaceBinding) extends AnyRef with Equality { if (prefix == "") throw new IllegalArgumentException("zero length prefix not allowed") @@ -41,6 +41,15 @@ case class NamespaceBinding(prefix: String, uri: String, parent: NamespaceBindin if (_uri == uri) prefix else parent getPrefix _uri override def toString(): String = sbToString(buildString(_, TopScope)) + override def canEqual(other: Any) = other match { + case _: NamespaceBinding => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case x: NamespaceBinding => (prefix == x.prefix) && (uri == x.uri) && (parent == x.parent) + case _ => false + } + def basisForHashCode: Seq[Any] = List(prefix, uri, parent) def buildString(stop: NamespaceBinding): String = sbToString(buildString(_, stop)) def buildString(sb: StringBuilder, stop: NamespaceBinding): Unit = { diff --git a/src/library/scala/xml/Node.scala b/src/library/scala/xml/Node.scala index 500c11e41d..5117bb9282 100644 --- a/src/library/scala/xml/Node.scala +++ b/src/library/scala/xml/Node.scala @@ -8,13 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.immutable.{List, Nil} -import collection.mutable.StringBuilder - /** * This object provides methods ... * @@ -22,7 +17,6 @@ import collection.mutable.StringBuilder * @version 1.0 */ object Node { - /** the constant empty attribute sequence */ final def NoAttributes: MetaData = Null @@ -30,7 +24,6 @@ object Node { val EmptyNamespace = "" def unapplySeq(n: Node) = Some((n.label, n.attributes, n.child)) - } /** @@ -116,6 +109,10 @@ abstract class Node extends NodeSeq { */ def child: Seq[Node] + /** Children which do not stringify to "" (needed for equality) + */ + def nonEmptyChildren: Seq[Node] = child filterNot (_.toString == "") + /** * Descendant axis (all descendants of this node, not including node itself) * includes all text nodes, element nodes, comments and processing instructions. @@ -129,41 +126,24 @@ abstract class Node extends NodeSeq { */ def descendant_or_self: List[Node] = this :: descendant - /** - * Returns true if x is structurally equal to this node. Compares prefix, - * label, attributes and children. - * - * @param x ... - * @return <code>true</code> if .. - */ - override def equals(x: Any): Boolean = x match { - case g: Group => false - case that: Node => - this.prefix == that.prefix && - this.label == that.label && - this.attributes == that.attributes && - this.scope == that.scope && - equalChildren(that) + override def canEqual(other: Any) = other match { + case x: Group => false + case x: Node => true case _ => false } - - // children comparison has to be done carefully - see bug #1773. - // It would conceivably be a better idea for a scala block which - // generates the empty string not to generate a child rather than - // our having to filter it later, but that approach would be more - // delicate to implement. - private def equalChildren(that: Node) = { - def noEmpties(xs: Seq[Node]) = xs filter (_.toString() != "") - noEmpties(this.child) sameElements noEmpties(that.child) + override def basisForHashCode: Seq[Any] = prefix :: label :: attributes :: nonEmptyChildren.toList + override def strict_==(other: Equality) = other match { + case _: Group => false + case x: Node => + (prefix == x.prefix) && + (label == x.label) && + (attributes == x.attributes) && + // (scope == x.scope) // note - original code didn't compare scopes so I left it as is. + (nonEmptyChildren sameElements x.nonEmptyChildren) + case _ => + false } - /** <p> - * Returns a hashcode. - * </p> - */ - override def hashCode(): Int = - Utility.hashCode(prefix, label, attributes.hashCode(), scope.hashCode(), child) - // implementations of NodeSeq methods /** diff --git a/src/library/scala/xml/NodeBuffer.scala b/src/library/scala/xml/NodeBuffer.scala index 49efe0a5ca..2cf999e8a4 100644 --- a/src/library/scala/xml/NodeBuffer.scala +++ b/src/library/scala/xml/NodeBuffer.scala @@ -8,11 +8,8 @@ // $Id$ - package scala.xml -import collection.{Iterator, Seq, Iterable} - /** * <p> * This class acts as a Buffer for nodes. If it is used as a sequence diff --git a/src/library/scala/xml/NodeSeq.scala b/src/library/scala/xml/NodeSeq.scala index 02c1b6ece8..3b56ba25e4 100644 --- a/src/library/scala/xml/NodeSeq.scala +++ b/src/library/scala/xml/NodeSeq.scala @@ -11,11 +11,9 @@ package scala.xml -import collection.immutable -import collection.immutable.{List, Nil, ::} -import collection.{Seq, SeqLike} -import collection.mutable.{Builder, ListBuffer} -import collection.generic.CanBuildFrom +import collection.{ mutable, immutable, generic, SeqLike } +import mutable.{ Builder, ListBuffer } +import generic.{ CanBuildFrom } /** This object ... * @@ -43,7 +41,7 @@ object NodeSeq { * @author Burak Emir * @version 1.0 */ -abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { +abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] with Equality { import NodeSeq.seqToNodeSeq // import view magic for NodeSeq wrappers /** Creates a list buffer as builder for this class */ @@ -56,12 +54,23 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { def apply(i: Int): Node = theSeq(i) def apply(f: Node => Boolean): NodeSeq = filter(f) - /** structural equality (XXX - this shatters any hope of hashCode equality) */ - override def equals(x: Any): Boolean = x match { - case z:Node => (length == 1) && z == apply(0) - case z:Seq[_] => sameElements(z) - case z:String => text == z - case _ => false + def xml_sameElements[A](that: Iterable[A]): Boolean = { + val these = this.iterator + val those = that.iterator + while (these.hasNext && those.hasNext) + if (these.next xml_!= those.next) + return false + + !these.hasNext && !those.hasNext + } + def basisForHashCode: Seq[Any] = theSeq + override def canEqual(other: Any) = other match { + case _: NodeSeq => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case x: NodeSeq => (length == x.length) && (theSeq sameElements x.theSeq) + case _ => false } /** Projection function. Similar to XPath, use <code>this \ "foo"</code> @@ -92,7 +101,7 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { if (uri == "" || key == "") fail else y.attribute(uri, key) } - else y.attribute(that.substring(1)) + else y.attribute(that drop 1) attr match { case Some(x) => Group(x) diff --git a/src/library/scala/xml/Null.scala b/src/library/scala/xml/Null.scala index a3246d4b57..d6f06fc3cd 100644 --- a/src/library/scala/xml/Null.scala +++ b/src/library/scala/xml/Null.scala @@ -12,70 +12,49 @@ package scala.xml import Utility.{ isNameStart } -import collection.Iterator -import collection.immutable.{Nil, List} -import collection.mutable.StringBuilder +/** Essentially, every method in here is a dummy, returning Zero[T]. + * It provides a backstop for the unusual collection defined by MetaData, + * sort of a linked list of tails. + */ case object Null extends MetaData { - - /** appends given MetaData items to this MetaData list */ - override def append(m: MetaData, scope: NamespaceBinding = TopScope): MetaData = m - - override def containedIn1(m: MetaData): Boolean = false - - /** returns its argument */ - def copy(next: MetaData) = next - override def iterator = Iterator.empty - + override def append(m: MetaData, scope: NamespaceBinding = TopScope): MetaData = m override def filter(f: MetaData => Boolean): MetaData = this + def copy(next: MetaData) = next def getNamespace(owner: Node) = null - final override def hasNext = false + override def hasNext = false def next = null def key = null def value = null - - final override def length = 0 - final override def length(i: Int) = i - def isPrefixed = false - /** deep equals method - XXX */ - override def equals(that: Any) = that match { - case m: MetaData => m.length == 0 - case _ => false - } + override def length = 0 + override def length(i: Int) = i - def equals1(that:MetaData) = that.length == 0 - - override def map(f: MetaData => Text): List[Text] = Nil + override def strict_==(other: Equality) = other match { + case x: MetaData => x.length == 0 + case _ => false + } + override def basisForHashCode: Seq[Any] = Nil - /** null */ + def apply(namespace: String, scope: NamespaceBinding, key: String) = null def apply(key: String) = { - if(!isNameStart(key charAt 0)) + if (!isNameStart(key.head)) throw new IllegalArgumentException("not a valid attribute name '"+key+"', so can never match !") + null } - /** gets value of qualified (prefixed) attribute with given key */ - def apply(namespace: String, scope: NamespaceBinding, key: String) = null - - override def hashCode(): Int = 0 - + def toString1(sb: StringBuilder) = () override def toString1(): String = "" - - //appends string representations of single attribute to StringBuilder - def toString1(sb:StringBuilder) = {} - override def toString(): String = "" override def buildString(sb: StringBuilder): StringBuilder = sb - override def wellformed(scope: NamespaceBinding) = true def remove(key: String) = this - def remove(namespace: String, scope: NamespaceBinding, key: String) = this } diff --git a/src/library/scala/xml/PCData.scala b/src/library/scala/xml/PCData.scala index 5cf4bda070..fa44591496 100644 --- a/src/library/scala/xml/PCData.scala +++ b/src/library/scala/xml/PCData.scala @@ -7,16 +7,9 @@ package scala.xml * and is to be preserved as CDATA section in the output. */ case class PCData(_data: String) extends Atom[String](_data) { - /* The following code is a derivative work of scala.xml.Text */ if (null == data) throw new IllegalArgumentException("tried to construct PCData with null") - final override def equals(x: Any) = x match { - case s: String => s.equals(data) - case s: Atom[_] => data == s.data - case _ => false - } - /** Returns text, with some characters escaped according to the XML * specification. * diff --git a/src/library/scala/xml/PrefixedAttribute.scala b/src/library/scala/xml/PrefixedAttribute.scala index a465e61ba3..d7c04ab6ad 100644 --- a/src/library/scala/xml/PrefixedAttribute.scala +++ b/src/library/scala/xml/PrefixedAttribute.scala @@ -8,13 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.mutable.StringBuilder - - /** prefixed attributes always have a non-null namespace. * * @param pre ... @@ -36,24 +31,12 @@ extends Attribute def this(pre: String, key: String, value: String, next: MetaData) = this(pre, key, Text(value), next) - /* - // the problem here is the fact that we cannot remove the proper attribute from - // next, and thus cannot guarantee that hashcodes are computed properly - def this(pre: String, key: String, value: scala.AllRef, next: MetaData) = - throw new UnsupportedOperationException("can't construct prefixed nil attributes") - */ - /** Returns a copy of this unprefixed attribute with the given * next field. */ def copy(next: MetaData) = new PrefixedAttribute(pre, key, value, next) - def equals1(m: MetaData) = - (m.isPrefixed && - (m.asInstanceOf[PrefixedAttribute].pre == pre) && - (m.key == key) && (m.value sameElements value)) - def getNamespace(owner: Node) = owner.getNamespace(pre) @@ -68,41 +51,8 @@ extends Attribute else next(namespace, scope, key) } - - /** returns true */ - final def isPrefixed = true - - /** returns the hashcode. - */ - override def hashCode() = - pre.hashCode() * 41 + key.hashCode() * 7 + next.hashCode() - - - /** appends string representation of only this attribute to stringbuffer */ - def toString1(sb:StringBuilder): Unit = if(value ne null) { - sb.append(pre) - sb.append(':') - sb.append(key) - sb.append('=') - val sb2 = new StringBuilder() - Utility.sequenceToXML(value, TopScope, sb2, true) - Utility.appendQuoted(sb2.toString(), sb) - } - - def wellformed(scope: NamespaceBinding): Boolean = - (null == next(scope.getURI(pre), scope, key) && - next.wellformed(scope)) - - def remove(key: String) = - copy(next.remove(key)) - - def remove(namespace: String, scope: NamespaceBinding, key: String): MetaData = - if (key == this.key && scope.getURI(pre) == namespace) - next - else - next.remove(namespace, scope, key) - } + object PrefixedAttribute { def unapply(x: PrefixedAttribute) = Some(x.pre, x.key, x.value, x.next) } diff --git a/src/library/scala/xml/PrettyPrinter.scala b/src/library/scala/xml/PrettyPrinter.scala index 17e7db679a..77199ca367 100644 --- a/src/library/scala/xml/PrettyPrinter.scala +++ b/src/library/scala/xml/PrettyPrinter.scala @@ -8,10 +8,8 @@ // $Id$ - package scala.xml -import scala.collection.Map import Utility.sbToString /** Class for pretty printing. After instantiating, you can use the @@ -39,7 +37,6 @@ class PrettyPrinter(width: Int, step: Int) { protected var items: List[Item] = Nil protected var cur = 0 - //protected var pmap:Map[String,String] = _ protected def reset() = { cur = 0 diff --git a/src/library/scala/xml/ProcInstr.scala b/src/library/scala/xml/ProcInstr.scala index 5a4e67e647..051fd499f4 100644 --- a/src/library/scala/xml/ProcInstr.scala +++ b/src/library/scala/xml/ProcInstr.scala @@ -9,7 +9,6 @@ // $Id$ package scala.xml -import collection.mutable.StringBuilder /** an XML node for processing instructions (PI) * diff --git a/src/library/scala/xml/SpecialNode.scala b/src/library/scala/xml/SpecialNode.scala index d40d829c4b..1688cd1e15 100644 --- a/src/library/scala/xml/SpecialNode.scala +++ b/src/library/scala/xml/SpecialNode.scala @@ -8,12 +8,8 @@ // $Id$ - package scala.xml -import collection.immutable.{List, Nil, ::} -import collection.mutable.StringBuilder - /** <p> * <code>SpecialNode</code> is a special XML node which * represents either text (PCDATA), a comment, a PI, or an entity ref. diff --git a/src/library/scala/xml/Text.scala b/src/library/scala/xml/Text.scala index 3090883bb8..5f0b010c9f 100644 --- a/src/library/scala/xml/Text.scala +++ b/src/library/scala/xml/Text.scala @@ -8,11 +8,8 @@ // $Id$ - package scala.xml -import collection.mutable.StringBuilder - // XXX This attempt to make Text not a case class revealed a bug in the pattern // matcher (see ticket #2883) so I've put the case back. (It was/is desirable that // it not be a case class because it is using the antipattern of passing constructor @@ -42,13 +39,6 @@ case class Text(_data: String) extends Atom[String](_data) if (_data == null) throw new IllegalArgumentException("tried to construct Text with null") - /** XXX More hashCode flailing. */ - final override def equals(x: Any) = x match { - case s:String => s == data - case s:Atom[_] => data == s.data - case _ => false - } - /** Returns text, with some characters escaped according to the XML * specification. * diff --git a/src/library/scala/xml/TextBuffer.scala b/src/library/scala/xml/TextBuffer.scala index 17c40aad2f..84c6c24146 100644 --- a/src/library/scala/xml/TextBuffer.scala +++ b/src/library/scala/xml/TextBuffer.scala @@ -8,12 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.mutable.StringBuilder -import collection.immutable.{List, Nil, ::} import Utility.isSpace object TextBuffer { diff --git a/src/library/scala/xml/TopScope.scala b/src/library/scala/xml/TopScope.scala index c638b80b2d..8b3c1383c9 100644 --- a/src/library/scala/xml/TopScope.scala +++ b/src/library/scala/xml/TopScope.scala @@ -10,8 +10,6 @@ package scala.xml -import collection.mutable.StringBuilder - /** top level namespace scope. only contains the predefined binding * for the "xml" prefix which is bound to * "http://www.w3.org/XML/1998/namespace" diff --git a/src/library/scala/xml/Unparsed.scala b/src/library/scala/xml/Unparsed.scala index a570b83fb5..d3c63172e8 100644 --- a/src/library/scala/xml/Unparsed.scala +++ b/src/library/scala/xml/Unparsed.scala @@ -22,13 +22,6 @@ class Unparsed(data: String) extends Atom[String](data) if (null == data) throw new IllegalArgumentException("tried to construct Unparsed with null") - /** XXX another hashCode fail */ - final override def equals(x: Any) = x match { - case s:String => s == data - case s:Atom[_] => data == s.data - case _ => false - } - /** returns text, with some characters escaped according to XML spec */ override def buildString(sb: StringBuilder) = sb append data } diff --git a/src/library/scala/xml/UnprefixedAttribute.scala b/src/library/scala/xml/UnprefixedAttribute.scala index 283cc3a1d0..a8720f13e1 100644 --- a/src/library/scala/xml/UnprefixedAttribute.scala +++ b/src/library/scala/xml/UnprefixedAttribute.scala @@ -8,13 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.mutable.StringBuilder - - /** Unprefixed attributes have the null namespace, and no prefix field * * @author Burak Emir @@ -25,6 +20,7 @@ class UnprefixedAttribute( next1: MetaData) extends Attribute { + final val pre = null val next = if (value ne null) next1 else next1.remove(key) /** same as this(key, Text(value), next) */ @@ -38,9 +34,6 @@ extends Attribute /** returns a copy of this unprefixed attribute with the given next field*/ def copy(next: MetaData) = new UnprefixedAttribute(key, value, next) - def equals1(m: MetaData) = - !m.isPrefixed && (m.key == key) && (m.value sameElements value) - final def getNamespace(owner: Node): String = null /** @@ -62,33 +55,6 @@ extends Attribute */ def apply(namespace: String, scope: NamespaceBinding, key: String): Seq[Node] = next(namespace, scope, key) - - override def hashCode() = - key.hashCode() * 7 + { if(value ne null) value.hashCode() * 53 else 0 } + next.hashCode() - - final def isPrefixed = false - - /** appends string representation of only this attribute to stringbuffer. - * - * @param sb .. - */ - def toString1(sb: StringBuilder): Unit = if (value ne null) { - sb.append(key) - sb.append('=') - val sb2 = new StringBuilder() - Utility.sequenceToXML(value, TopScope, sb2, true) - Utility.appendQuoted(sb2.toString(), sb) - } - - def wellformed(scope: NamespaceBinding): Boolean = - (null == next(null, scope, key)) && next.wellformed(scope) - - def remove(key: String) = - if (this.key == key) next else copy(next.remove(key)) - - def remove(namespace: String, scope: NamespaceBinding, key: String): MetaData = - next.remove(namespace, scope, key) - } object UnprefixedAttribute { def unapply(x: UnprefixedAttribute) = Some(x.key, x.value, x.next) diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 138a704957..48a23dc389 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -11,8 +11,8 @@ package scala.xml -import collection.mutable.{Set, HashSet, StringBuilder} -import collection.Seq +import collection.mutable +import mutable.{ Set, HashSet } import parsing.XhtmlEntities /** @@ -149,7 +149,7 @@ object Utility extends AnyRef with parsing.TokenTests * @param nodes ... * @return ... */ - def collectNamespaces(nodes: Seq[Node]): Set[String] = + def collectNamespaces(nodes: Seq[Node]): mutable.Set[String] = nodes.foldLeft(new HashSet[String]) { (set, x) => collectNamespaces(x, set) ; set } /** @@ -158,7 +158,7 @@ object Utility extends AnyRef with parsing.TokenTests * @param n ... * @param set ... */ - def collectNamespaces(n: Node, set: Set[String]) { + def collectNamespaces(n: Node, set: mutable.Set[String]) { if (n.doCollectNamespaces) { set += n.namespace for (a <- n.attributes) a match { diff --git a/src/library/scala/xml/XML.scala b/src/library/scala/xml/XML.scala index 1e85d4ae06..1395f7426f 100644 --- a/src/library/scala/xml/XML.scala +++ b/src/library/scala/xml/XML.scala @@ -11,12 +11,10 @@ package scala.xml -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 parsing.NoBindingFactoryAdapter +import factory.XMLLoader +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 diff --git a/src/library/scala/xml/dtd/ContentModel.scala b/src/library/scala/xml/dtd/ContentModel.scala index d5d4b95cce..772d8ec599 100644 --- a/src/library/scala/xml/dtd/ContentModel.scala +++ b/src/library/scala/xml/dtd/ContentModel.scala @@ -13,10 +13,7 @@ package scala.xml package dtd import util.regexp.WordExp -import util.automata.{DetWordAutom, SubsetConstruction, WordBerrySethi} -import collection.mutable.{HashSet, StringBuilder} -import collection.immutable.{List, Nil} -import collection.Seq +import util.automata._ import Utility.sbToString import PartialFunction._ diff --git a/src/library/scala/xml/dtd/ContentModelParser.scala b/src/library/scala/xml/dtd/ContentModelParser.scala index c260a9fc46..2b0df3f6a5 100644 --- a/src/library/scala/xml/dtd/ContentModelParser.scala +++ b/src/library/scala/xml/dtd/ContentModelParser.scala @@ -8,12 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.immutable.List - /** Parser for regexps (content models in DTD element declarations) */ object ContentModelParser extends Scanner { // a bit too permissive concerning #PCDATA diff --git a/src/library/scala/xml/dtd/DTD.scala b/src/library/scala/xml/dtd/DTD.scala index 14c16f8489..0fde1188f3 100644 --- a/src/library/scala/xml/dtd/DTD.scala +++ b/src/library/scala/xml/dtd/DTD.scala @@ -8,31 +8,25 @@ // $Id$ - package scala.xml package dtd -import scala.collection.mutable.{HashMap, Map} +import collection.mutable +import mutable.HashMap /** A document type declaration. * * @author Burak Emir */ abstract class DTD { - - var externalID: ExternalID = null - - def notations: Seq[NotationDecl] = Nil - + var externalID: ExternalID = null + var decls: List[Decl] = Nil + def notations: Seq[NotationDecl] = Nil def unparsedEntities: Seq[EntityDecl] = Nil - var elem: Map[String, ElemDecl] = new HashMap[String, ElemDecl]() - - var attr: Map[String, AttListDecl] = new HashMap[String, AttListDecl]() - - var ent: Map[String, EntityDecl] = new HashMap[String, EntityDecl]() - - var decls: List[Decl] = Nil + var elem: mutable.Map[String, ElemDecl] = new HashMap[String, ElemDecl]() + var attr: mutable.Map[String, AttListDecl] = new HashMap[String, AttListDecl]() + var ent: mutable.Map[String, EntityDecl] = new HashMap[String, EntityDecl]() override def toString() = "DTD [\n%s%s]".format( diff --git a/src/library/scala/xml/dtd/Decl.scala b/src/library/scala/xml/dtd/Decl.scala index 25ee30b356..ddc179b69f 100644 --- a/src/library/scala/xml/dtd/Decl.scala +++ b/src/library/scala/xml/dtd/Decl.scala @@ -8,14 +8,10 @@ // $Id$ - package scala.xml package dtd import Utility.sbToString -import collection.immutable.List -import collection.mutable.StringBuilder - abstract class Decl diff --git a/src/library/scala/xml/dtd/DocType.scala b/src/library/scala/xml/dtd/DocType.scala index dab1d9ff6b..7da38b3e73 100644 --- a/src/library/scala/xml/dtd/DocType.scala +++ b/src/library/scala/xml/dtd/DocType.scala @@ -8,12 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.Seq - /** An XML node for document type declaration. * * @author Burak Emir diff --git a/src/library/scala/xml/dtd/ExternalID.scala b/src/library/scala/xml/dtd/ExternalID.scala index 784273083a..b0d311e54a 100644 --- a/src/library/scala/xml/dtd/ExternalID.scala +++ b/src/library/scala/xml/dtd/ExternalID.scala @@ -8,14 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.immutable.{List, Nil} -import collection.mutable.StringBuilder - - /** an ExternalIDs - either PublicID or SystemID * * @author Burak Emir diff --git a/src/library/scala/xml/dtd/Scanner.scala b/src/library/scala/xml/dtd/Scanner.scala index 1a45a186a0..7b3e2acfe0 100644 --- a/src/library/scala/xml/dtd/Scanner.scala +++ b/src/library/scala/xml/dtd/Scanner.scala @@ -8,13 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.{Seq, Iterator} -import collection.immutable.{List, Nil} - /** Scanner for regexps (content models in DTD element declarations) * todo: cleanup */ diff --git a/src/library/scala/xml/factory/Binder.scala b/src/library/scala/xml/factory/Binder.scala index caad009b9b..3996ef2d36 100644 --- a/src/library/scala/xml/factory/Binder.scala +++ b/src/library/scala/xml/factory/Binder.scala @@ -12,7 +12,7 @@ package scala.xml package factory -import scala.xml.parsing.ValidatingMarkupHandler +import parsing.ValidatingMarkupHandler /** * @author Burak Emir diff --git a/src/library/scala/xml/factory/NodeFactory.scala b/src/library/scala/xml/factory/NodeFactory.scala index 45dac6ccda..2dd52242db 100644 --- a/src/library/scala/xml/factory/NodeFactory.scala +++ b/src/library/scala/xml/factory/NodeFactory.scala @@ -12,11 +12,7 @@ package scala.xml package factory import parsing.{ FactoryAdapter, NoBindingFactoryAdapter } -import collection.Seq -import collection.immutable.{List, Nil} -import org.xml.sax.InputSource import java.io.{ InputStream, Reader, StringReader, File, FileDescriptor, FileInputStream } -import javax.xml.parsers.{ SAXParser, SAXParserFactory } trait NodeFactory[A <: Node] { diff --git a/src/library/scala/xml/factory/XMLLoader.scala b/src/library/scala/xml/factory/XMLLoader.scala index a1bca21b40..8bb0cf4188 100644 --- a/src/library/scala/xml/factory/XMLLoader.scala +++ b/src/library/scala/xml/factory/XMLLoader.scala @@ -11,11 +11,9 @@ package scala.xml package factory +import javax.xml.parsers.SAXParserFactory import parsing.{ FactoryAdapter, NoBindingFactoryAdapter } -import org.xml.sax.InputSource import java.io.{ InputStream, Reader, StringReader, File, FileDescriptor, FileInputStream } -import javax.xml.parsers.{ SAXParser, SAXParserFactory } -import java.net.URL /** Presents collection of XML loading methods which use the parser * created by "def parser". diff --git a/src/library/scala/xml/include/sax/Main.scala b/src/library/scala/xml/include/sax/Main.scala index e7e986e0f8..3aa281451c 100644 --- a/src/library/scala/xml/include/sax/Main.scala +++ b/src/library/scala/xml/include/sax/Main.scala @@ -13,11 +13,10 @@ package include.sax import scala.xml.include._ import scala.util.control.Exception.{ catching, ignoring } -import org.xml.sax.{ SAXException, SAXParseException, EntityResolver, XMLReader } +import org.xml.sax.XMLReader import org.xml.sax.helpers.XMLReaderFactory object Main { - private val xercesClass = "org.apache.xerces.parsers.SAXParser" private val namespacePrefixes = "http://xml.org/sax/features/namespace-prefixes" private val lexicalHandler = "http://xml.org/sax/properties/lexical-handler" @@ -35,7 +34,7 @@ object Main { val parser: XMLReader = saxe[XMLReader](XMLReaderFactory.createXMLReader()) getOrElse ( - saxe[XMLReader](XMLReaderFactory.createXMLReader(xercesClass)) getOrElse ( + saxe[XMLReader](XMLReaderFactory.createXMLReader(XercesClassName)) getOrElse ( return error("Could not find an XML parser") ) ) diff --git a/src/library/scala/xml/include/sax/XIncludeFilter.scala b/src/library/scala/xml/include/sax/XIncludeFilter.scala index b469086e73..6e64fa9aa5 100644 --- a/src/library/scala/xml/include/sax/XIncludeFilter.scala +++ b/src/library/scala/xml/include/sax/XIncludeFilter.scala @@ -12,11 +12,10 @@ package scala.xml package include.sax import scala.xml.include._ -import org.xml.sax.{ Attributes, SAXException, XMLReader, EntityResolver, Locator } +import org.xml.sax.{ Attributes, XMLReader, Locator } import org.xml.sax.helpers.{ XMLReaderFactory, XMLFilterImpl, NamespaceSupport, AttributesImpl } -import java.net.{ URL, URLConnection, MalformedURLException } -import java.io.{ UnsupportedEncodingException, IOException, InputStream, BufferedInputStream, InputStreamReader } +import java.io.{ InputStream, BufferedInputStream, InputStreamReader } import java.util.Stack /** @@ -351,61 +350,49 @@ class XIncludeFilter extends XMLFilterImpl { be downloaded from the specified URL. */ private def includeXMLDocument(url: String) { - var source: URL = null - try { - val base = bases.peek().asInstanceOf[URL] - source = new URL(base, url) - } - catch { - case e:MalformedURLException => - val ex = new UnavailableResourceException("Unresolvable URL " + url - + getLocation()); - ex.setRootCause(e) - throw new SAXException("Unresolvable URL " + url + getLocation(), ex) - } + val source = + try new URL(bases.peek(), url) + catch { + case e: MalformedURLException => + val ex = new UnavailableResourceException("Unresolvable URL " + url + getLocation()) + ex setRootCause e + throw new SAXException("Unresolvable URL " + url + getLocation(), ex) + } try { - // make this more robust - var parser: XMLReader = null - try { - parser = XMLReaderFactory.createXMLReader() - } catch { - case e:SAXException => - try { - parser = XMLReaderFactory.createXMLReader( - "org.apache.xerces.parsers.SAXParser" - ); - } catch { - case e2: SAXException => - System.err.println("Could not find an XML parser") - } - } - if(parser != null) { - parser.setContentHandler(this) - val resolver = this.getEntityResolver() - if (resolver != null) parser.setEntityResolver(resolver); - // save old level and base - val previousLevel = level - this.level = 0 - if (bases.contains(source)) { - val e = new CircularIncludeException( - "Circular XInclude Reference to " + source + getLocation() - ); - throw new SAXException("Circular XInclude Reference", e) + val parser: XMLReader = + try XMLReaderFactory.createXMLReader() + catch { + case e: SAXException => + try XMLReaderFactory.createXMLReader(XercesClassName) + catch { case _: SAXException => return System.err.println("Could not find an XML parser") } } - bases.push(source) - atRoot = true - parser.parse(source.toExternalForm()) - // restore old level and base - this.level = previousLevel - bases.pop() - } + + parser setContentHandler this + val resolver = this.getEntityResolver() + if (resolver != null) + parser setEntityResolver resolver + + // save old level and base + val previousLevel = level + this.level = 0 + if (bases contains source) + throw new SAXException( + "Circular XInclude Reference", + new CircularIncludeException("Circular XInclude Reference to " + source + getLocation()) + ) + + bases push source + atRoot = true + parser parse source.toExternalForm() + + // restore old level and base + this.level = previousLevel + bases.pop() } catch { - case e:IOException => - throw new SAXException("Document not found: " - + source.toExternalForm() + getLocation(), e) + case e: IOException => + throw new SAXException("Document not found: " + source.toExternalForm() + getLocation(), e) } - } } diff --git a/src/library/scala/xml/include/sax/XIncluder.scala b/src/library/scala/xml/include/sax/XIncluder.scala index 3417dd78f0..bd9da10c59 100644 --- a/src/library/scala/xml/include/sax/XIncluder.scala +++ b/src/library/scala/xml/include/sax/XIncluder.scala @@ -10,22 +10,13 @@ package scala.xml package include.sax + import scala.xml.include._ +import collection.mutable.Stack -import org.xml.sax.SAXException -import org.xml.sax.SAXParseException -import org.xml.sax.ContentHandler -import org.xml.sax.EntityResolver -import org.xml.sax.helpers.XMLReaderFactory -import org.xml.sax.XMLReader -import org.xml.sax.Locator -import org.xml.sax.Attributes +import org.xml.sax.{ ContentHandler, XMLReader, Locator, Attributes } import org.xml.sax.ext.LexicalHandler - -import java.io.{File, IOException, OutputStream, OutputStreamWriter, - UnsupportedEncodingException, Writer} -import java.net.{MalformedURLException, URL} -import java.util.Stack +import java.io.{ File, OutputStream, OutputStreamWriter, Writer } /** XIncluder is a SAX <code>ContentHandler</code> * that writes its XML document onto an output stream after resolving @@ -35,8 +26,7 @@ import java.util.Stack * based on Eliotte Rusty Harold's SAXXIncluder * </p> */ -class XIncluder(outs:OutputStream, encoding:String) extends Object -with ContentHandler with LexicalHandler { +class XIncluder(outs: OutputStream, encoding: String) extends ContentHandler with LexicalHandler { var out = new OutputStreamWriter(outs, encoding) @@ -153,7 +143,7 @@ with ContentHandler with LexicalHandler { def startDTD(name: String, publicID: String, systemID: String) { inDTD = true // if this is the source document, output a DOCTYPE declaration - if (entities.size() == 0) { + if (entities.isEmpty) { var id = "" if (publicID != null) id = " PUBLIC \"" + publicID + "\" \"" + systemID + '"'; else if (systemID != null) id = " SYSTEM \"" + systemID + '"'; @@ -169,7 +159,7 @@ with ContentHandler with LexicalHandler { def endDTD() {} def startEntity(name: String) { - entities.push(name) + entities push name } def endEntity(name: String) { diff --git a/src/library/scala/xml/package.scala b/src/library/scala/xml/package.scala new file mode 100644 index 0000000000..33639ed978 --- /dev/null +++ b/src/library/scala/xml/package.scala @@ -0,0 +1,18 @@ +package scala + +package object xml { + val XercesClassName = "org.apache.xerces.parsers.SAXParser" + + type SAXException = org.xml.sax.SAXException + type SAXParseException = org.xml.sax.SAXParseException + type EntityResolver = org.xml.sax.EntityResolver + type InputSource = org.xml.sax.InputSource + + type SAXParser = javax.xml.parsers.SAXParser + + type IOException = java.io.IOException + type UnsupportedEncodingException = java.io.UnsupportedEncodingException + + type URL = java.net.URL + type MalformedURLException = java.net.MalformedURLException +}
\ 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 a83f9677a1..6960e05d25 100644 --- a/src/library/scala/xml/parsing/FactoryAdapter.scala +++ b/src/library/scala/xml/parsing/FactoryAdapter.scala @@ -12,20 +12,15 @@ package scala.xml package parsing -import java.io.{InputStream, Reader, File, FileDescriptor, FileInputStream} -import collection.mutable.{Stack, StringBuilder} -import collection.immutable.{List, Nil} -import collection.{Seq, Iterator} +import java.io.{ InputStream, Reader, File, FileDescriptor, FileInputStream } +import collection.mutable.Stack -import org.xml.sax.{ Attributes, InputSource } +import org.xml.sax.Attributes import org.xml.sax.helpers.DefaultHandler -import javax.xml.parsers.{ SAXParser, SAXParserFactory } // can be mixed into FactoryAdapter if desired trait ConsoleErrorHandler extends DefaultHandler { - import org.xml.sax.SAXParseException - // ignore warning, crimson warns even for entity resolution! override def warning(ex: SAXParseException): Unit = { } override def error(ex: SAXParseException): Unit = printError("Error", ex) diff --git a/src/library/scala/xml/parsing/MarkupHandler.scala b/src/library/scala/xml/parsing/MarkupHandler.scala index a0058e8bc4..75c7958c38 100644 --- a/src/library/scala/xml/parsing/MarkupHandler.scala +++ b/src/library/scala/xml/parsing/MarkupHandler.scala @@ -12,7 +12,8 @@ package scala.xml package parsing -import scala.collection.mutable.{HashMap, Map} +import collection.mutable +import mutable.HashMap import scala.io.Source import scala.util.logging.Logged import scala.xml.dtd._ @@ -32,7 +33,7 @@ abstract class MarkupHandler extends Logged val isValidating: Boolean = false var decls: List[Decl] = Nil - var ent: Map[String, EntityDecl] = new HashMap[String, EntityDecl]() + var ent: mutable.Map[String, EntityDecl] = new HashMap[String, EntityDecl]() def lookupElemDecl(Label: String): ElemDecl = { for (z @ ElemDecl(Label, _) <- decls) diff --git a/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala b/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala index 05d535155b..083465bc41 100644 --- a/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala +++ b/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala @@ -12,10 +12,6 @@ package scala.xml package parsing import factory.NodeFactory -import collection.Seq -import collection.immutable.List -import org.xml.sax.InputSource -import javax.xml.parsers.{ SAXParser, SAXParserFactory } /** nobinding adaptor providing callbacks to parser to create elements. * implements hash-consing diff --git a/src/library/scala/xml/parsing/TokenTests.scala b/src/library/scala/xml/parsing/TokenTests.scala index e41cff20a3..13500e8510 100644 --- a/src/library/scala/xml/parsing/TokenTests.scala +++ b/src/library/scala/xml/parsing/TokenTests.scala @@ -12,8 +12,6 @@ package scala.xml package parsing -import collection.Seq -import collection.immutable.List /** * Helper functions for parsing XML fragments */ diff --git a/src/library/scala/xml/parsing/XhtmlEntities.scala b/src/library/scala/xml/parsing/XhtmlEntities.scala index dbc2ae0621..6e35aa9606 100644 --- a/src/library/scala/xml/parsing/XhtmlEntities.scala +++ b/src/library/scala/xml/parsing/XhtmlEntities.scala @@ -8,11 +8,10 @@ // $Id$ - package scala.xml package parsing -import scala.xml.dtd.{IntDef, ParsedEntityDecl} +import scala.xml.dtd.{ IntDef, ParsedEntityDecl } /** <p> * (c) David Pollak 2007 WorldWide Conferencing, LLC. diff --git a/test/files/jvm/xml01.scala b/test/files/jvm/xml01.scala index e305f516d7..56e1c4ef96 100644 --- a/test/files/jvm/xml01.scala +++ b/test/files/jvm/xml01.scala @@ -25,20 +25,18 @@ object Test extends Application with Assert { override def text = "" } - assertSameElements(List(3), List(3)) - println("equality") - assertEquals(c, parsedxml11) - assertEquals(parsedxml1, parsedxml11) - assertSameElements(List(parsedxml1), List(parsedxml11)) - assertSameElements(Array(parsedxml1).toList, List(parsedxml11)) + assertEqualsXML(c, parsedxml11) + assertEqualsXML(parsedxml1, parsedxml11) + assertSameElementsXML(List(parsedxml1), List(parsedxml11)) + assertSameElementsXML(Array(parsedxml1).toList, List(parsedxml11)) val x2 = "<book><author>Peter Buneman</author><author>Dan Suciu</author><title>Data on ze web</title></book>"; val i = new InputSource(new StringReader(x2)) val x2p = XML.load(i) - assertEquals(x2p, Elem(null, "book" , e, sc, + assertEqualsXML(x2p, Elem(null, "book" , e, sc, Elem(null, "author", e, sc,Text("Peter Buneman")), Elem(null, "author", e, sc,Text("Dan Suciu")), Elem(null, "title" , e, sc,Text("Data on ze web")))); @@ -51,9 +49,9 @@ object Test extends Application with Assert { println("xpath \\") - assertSameElements(parsedxml1 \ "_" , List(Elem(null,"world", e, sc))) + assertSameElementsXML(parsedxml1 \ "_" , List(Elem(null,"world", e, sc))) - assertSameElements(parsedxml1 \ "world", List(Elem(null,"world", e, sc))) + assertSameElementsXML(parsedxml1 \ "world", List(Elem(null,"world", e, sc))) /* Console.println( parsedxml2 \ "_" ); @@ -63,7 +61,7 @@ object Test extends Application with Assert { }; */ - assertSameElements( + assertSameElementsXML( parsedxml2 \ "_" , List( @@ -77,7 +75,7 @@ object Test extends Application with Assert { ); assertEquals( (parsedxml2 \ "author").length, 0 ); - assertSameElements( + assertSameElementsXML( parsedxml2 \ "book", List( @@ -91,7 +89,7 @@ object Test extends Application with Assert { ) ); - assertSameElements( + assertSameElementsXML( parsedxml2 \ "_" \ "_", @@ -104,7 +102,7 @@ object Test extends Application with Assert { ) ); - assertSameElements( + assertSameElementsXML( parsedxml2 \ "_" \ "author", @@ -116,11 +114,11 @@ object Test extends Application with Assert { ); - assertSameElements( (parsedxml2 \ "_" \ "_" \ "author"), List() ); + assertSameElementsXML( (parsedxml2 \ "_" \ "_" \ "author"), List() ); Console.println("xpath \\\\ DESCENDANTS"); - assertSameElements( + assertSameElementsXML( parsedxml2 \\ "author", @@ -133,7 +131,7 @@ object Test extends Application with Assert { ); - assertSameElements( + assertSameElementsXML( parsedxml2 \\ "title", @@ -144,10 +142,10 @@ object Test extends Application with Assert { println( - (parsedxml2 \\ "book" ){ n:Node => n \ "title" == "Data on ze web" } + (parsedxml2 \\ "book" ){ n:Node => (n \ "title") xml_== "Data on ze web" } ); - assertEquals( + assertEqualsXML( (new NodeSeq { val theSeq = List( parsedxml2 ) }) \\ "_", @@ -191,13 +189,13 @@ object Test extends Application with Assert { val zz1 = <xml:group><a/><b/><c/></xml:group> - assertTrue(zx1 == zz1) + assertTrue(zx1 xml_== zz1) assertTrue(zz1.length == 3) // unparsed - val uup = <xml:unparsed>&<<>""^%@$!#</xml:unparsed> - assertTrue(uup == "&<<>\"\"^%@$!#") + // val uup = <xml:unparsed>&<<>""^%@$!#</xml:unparsed> + // assertTrue(uup == "&<<>\"\"^%@$!#") // test unicode escapes backslash u println("attribute value normalization") diff --git a/test/files/jvm/xml02.scala b/test/files/jvm/xml02.scala index 0cbeb27ce2..11f77cc90f 100644 --- a/test/files/jvm/xml02.scala +++ b/test/files/jvm/xml02.scala @@ -18,10 +18,10 @@ object Test extends TestConsoleMain { object XmlEx extends TestCase("attributes") with Assert { override def runTest = { - assertTrue("@one", ax \ "@foo" == "bar") // uses NodeSeq.view! - assertTrue("@two", ax \ "@foo" == xml.Text("bar")) // dto. - assertTrue("@three", bx \ "@foo" == "bar&x") // dto. - assertTrue ("@four", (bx \ "@foo") sameElements List(xml.Text("bar&x"))) + assertTrue("@one", (ax \ "@foo") xml_== "bar") // uses NodeSeq.view! + assertTrue("@two", (ax \ "@foo") xml_== xml.Text("bar")) // dto. + assertTrue("@three", (bx \ "@foo") xml_== "bar&x") // dto. + assertTrue ("@four", (bx \ "@foo") xml_sameElements List(xml.Text("bar&x"))) assertEquals("@five", "<hello foo=\"bar&x\"></hello>", bx.toString) } } @@ -29,8 +29,8 @@ object Test extends TestConsoleMain { object XmlEy extends TestCase("attributes with namespace") with Assert { override def runTest = { val z = ax \ "@{the namespace from outer space}foo" - assertTrue("@six", ax \ "@{the namespace from outer space}foo" == "baz") - assertTrue("@eight", cx \ "@{the namespace from outer space}foo" == "baz") + assertTrue("@six", (ax \ "@{the namespace from outer space}foo") xml_== "baz") + assertTrue("@eight", (cx \ "@{the namespace from outer space}foo") xml_== "baz") try { ax \ "@" @@ -58,8 +58,8 @@ object Test extends TestConsoleMain { override def runTest = { assertTrue(<hello/> match { case <hello/> => true; case _ => false; }) assertTrue(<x:ga xmlns:x="z"/> match { case <x:ga/> => true; case _ => false; }); - assertTrue(Utility.trim(cx) match { case n @ <hello>crazy text world</hello> if n \ "@foo" == "bar" => true; }) - assertTrue(Utility.trim(cx) match { case n @ <z:hello>crazy text world</z:hello> if n \ "@foo" == "bar" => true; }) + assertTrue(Utility.trim(cx) match { case n @ <hello>crazy text world</hello> if (n \ "@foo") xml_== "bar" => true; }) + assertTrue(Utility.trim(cx) match { case n @ <z:hello>crazy text world</z:hello> if (n \ "@foo") xml_== "bar" => true; }) } } diff --git a/test/files/jvm/xmlstuff.scala b/test/files/jvm/xmlstuff.scala index 46faf283dc..6e711a0f86 100644 --- a/test/files/jvm/xmlstuff.scala +++ b/test/files/jvm/xmlstuff.scala @@ -64,9 +64,9 @@ passed ok Text(x.attributes("value").toString + y.attributes("bazValue").toString+ "!") }; val pelems_2 = new NodeSeq { val theSeq = List(Text("38!"),Text("58!")) }; - assertSameElements(pelems_1, pelems_2) + assertSameElementsXML(pelems_1, pelems_2) - assertEquals(p \\ "@bazValue", Text("8")) + assertEqualsXML(p \\ "@bazValue", Text("8")) val books = <bks> @@ -97,7 +97,7 @@ passed ok println( new scala.xml.PrettyPrinter(80, 5).formatNodes ( for (t <- books \\ "title"; r <- reviews \\ "entry" - if r \ "title" == t) yield + if (r \ "title") xml_== t) yield <result> { t } { r \ "remarks" } @@ -139,7 +139,7 @@ val addrBook = println( new scala.xml.PrettyPrinter(80, 5).formatNodes ( for (t <- addrBook \\ "entry"; r <- phoneBook \\ "entry" - if t \ "name" == r \ "name") yield + if (t \ "name") xml_== (r \ "name")) yield <result> { t.child } { r \ "phone" } diff --git a/test/files/run/t1773.scala b/test/files/run/t1773.scala index 81c6005f86..4a4aaba1f0 100644 --- a/test/files/run/t1773.scala +++ b/test/files/run/t1773.scala @@ -8,5 +8,5 @@ object Test extends Application <a>{ if (true) "" else "I like turtles" }</a> ) - for (x1 <- xs; x2 <- xs) assert (x1 == x2) + for (x1 <- xs; x2 <- xs) assert (x1 xml_== x2) } |