scala.xml.Node.scala Maven / Gradle / Ivy
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
// $Id$
package scala.xml
/**
* This object provides methods ...
*
* @author Burak Emir
* @version 1.0
*/
object Node {
/** the constant empty attribute sequence */
final def NoAttributes: MetaData = Null
/** the empty namespace */
val EmptyNamespace = ""
def unapplySeq(n: Node) = Some((n.label, n.attributes, n.child))
}
/**
* An abstract class representing XML with nodes of a labelled tree.
* This class contains an implementation of a subset of XPath for navigation.
*
* @author Burak Emir and others
* @version 1.1
*/
abstract class Node extends NodeSeq {
/** prefix of this node */
def prefix: String = null
/** label of this node. I.e. "foo" for <foo/>) */
def label: String
/** used internally. Atom/Molecule = -1 PI = -2 Comment = -3 EntityRef = -5
*/
def isAtom = this.isInstanceOf[Atom[_]]
/** The logic formerly found in typeTag$, as best I could infer it. */
def doCollectNamespaces = true // if (tag >= 0) DO collect namespaces
def doTransform = true // if (tag < 0) DO NOT transform
/**
* method returning the namespace bindings of this node. by default, this
* is TopScope, which means there are no namespace bindings except the
* predefined one for "xml".
*/
def scope: NamespaceBinding = TopScope
/**
* convenience, same as getNamespace(this.prefix)
*/
def namespace = getNamespace(this.prefix)
/**
* Convenience method, same as scope.getURI(pre)
but additionally
* checks if scope is null
.
*
* @param pre the prefix whose namespace name we would like to obtain
* @return the namespace if scope != null
and prefix was
* found, else null
*/
def getNamespace(pre: String): String = if (scope eq null) null else scope.getURI(pre)
/**
* Convenience method, looks up an unprefixed attribute in attributes of this node.
* Same as attributes.getValue(key)
*
* @param key of queried attribute.
* @return value of UnprefixedAttribute
with given key
* in attributes, if it exists, otherwise null
.
*/
final def attribute(key: String): Option[Seq[Node]] = attributes.get(key)
/**
* Convenience method, looks up a prefixed attribute in attributes of this node.
* Same as attributes.getValue(uri, this, key)
*
* @param uri namespace of queried attribute (may not be null).
* @param key of queried attribute.
* @return value of PrefixedAttribute
with given namespace
* and given key, otherwise null
.
*/
final def attribute(uri: String, key: String): Option[Seq[Node]] =
attributes.get(uri, this, key)
/**
* Returns attribute meaning all attributes of this node, prefixed and
* unprefixed, in no particular order. In class Node
, this
* defaults to Null
(the empty attribute list).
*
* @return all attributes of this node
*/
def attributes: MetaData = Null
/**
* Returns child axis i.e. all children of this node.
*
* @return all children of this node
*/
def child: Seq[Node]
/**
* Descendant axis (all descendants of this node, not including node itself)
* includes all text nodes, element nodes, comments and processing instructions.
*/
def descendant: List[Node] =
child.toList.flatMap { x => x::x.descendant }
/**
* Descendant axis (all descendants of this node, including thisa node)
* includes all text nodes, element nodes, comments and processing instructions.
*/
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 true
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 &&
equalChildren(that)
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)
}
/**
* Returns a hashcode. The default implementation here calls only
* super.hashcode (which is the same as for objects). A more useful
* implementation can be invoked by calling
* Utility.hashCode(pre, label, attributes.hashCode(), child)
.
*
*/
override def hashCode(): Int = super.hashCode
// implementations of NodeSeq methods
/**
* returns a sequence consisting of only this node
*/
def theSeq: Seq[Node] = this :: Nil
/**
* String representation of this node
*
* @param stripComment if true, strips comment nodes from result
* @return ...
*/
def buildString(stripComments: Boolean): String =
Utility.toXML(this, stripComments = stripComments).toString
/**
* Same as toString(false)
.
*
* @see toString(Boolean)
*/
override def toString(): String = buildString(false)
/**
* Appends qualified name of this node to StringBuilder
.
*
* @param sb ...
* @return ...
*/
def nameToString(sb: StringBuilder): StringBuilder = {
if (null != prefix) {
sb.append(prefix)
sb.append(':')
}
sb.append(label)
}
/**
* Returns a type symbol (e.g. DTD, XSD), default null
.
*/
def xmlType(): TypeSymbol = null
/**
* Returns a text representation of this node. Note that this is not equivalent to
* the XPath node-test called text(), it is rather an implementation of the
* XPath function string()
* Martin to Burak: to do: if you make this method abstract, the compiler will now
* complain if there's no implementation in a subclass. Is this what we want? Note that
* this would break doc/DocGenator and doc/ModelToXML, with an error message like:
doc\DocGenerator.scala:1219: error: object creation impossible, since there is a deferred declaration of method text in class Node of type => String which is not implemented in a subclass
new SpecialNode {
^
*/
override def text: String = super.text
}