scala.xml.Node.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-library Show documentation
Show all versions of scala-library Show documentation
Standard library for the Scala Programming Language
/* __ *\
** ________ ___ / / ___ Scala API **
** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
** /____/\___/_/ |_/____/_/ | | **
** |/ **
\* */
package scala.xml
/** This singleton object contains the `unapplySeq` method for
* convenient deconstruction.
*
* @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]
/** 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.
*/
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
override def canEqual(other: Any) = other match {
case x: Group => false
case x: Node => true
case _ => false
}
override protected 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
}
// implementations of NodeSeq methods
/**
* returns a sequence consisting of only this node
*/
def theSeq: Seq[Node] = this :: Nil
/**
* String representation of this node
*
* @param stripComments if true, strips comment nodes from result
*/
def buildString(stripComments: Boolean): String =
Utility.serialize(this, stripComments = stripComments).toString
/**
* Same as `toString('''false''')`.
*/
override def toString(): String = buildString(false)
/**
* Appends qualified name of this node to `StringBuilder`.
*/
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
}