eu.cdevreeze

yaidom

package yaidom

Introduction

Yet another immutable DOM-like API. Hence the name yaidom. This is not an implementation of W3C DOM. Instead, this is a Scala-ish DOM-like API. Foremost, that means that this API is centered around Scala Collections of immutable nodes.

By design, some characteristics of this API are:

The yaidom API is most suitable for processing "data-oriented" XML, roughly having the following properties:

That is not to say that yaidom can only be used for processing such "data-oriented" XML.

Yaidom is not a very ambitious API:

Yaidom has been inspired by Anti-XML. The Anti-XML library tackles some weaknesses of Scala's standard XML API, w.r.t. robustness, ease of use and performance. Yaidom tries to achieve the same (in a different way), but yaidom is less ambitious, foremost in not offering any XPath(-like) support.

Different element types in yaidom

Yaidom considers XML to be trees of nodes, rather than text strings obeying "XML rules". Think InfoSet and DOM, rather than the XML spec. By considering XML to be node trees, round-tripping (from XML string to DOM-like tree, and back) cannot be lossless. Again, if lossless round-tripping is important (like is the case for XML editors), yaidom (like DOM) may not be a good fit.

Yet yaidom has more than just one type of (DOM-like) element. First of all, yaidom distinguishes between:

Concrete element classes in yaidom that mix in trait eu.cdevreeze.yaidom.ParentElemLike (or sub-traits) are:

Often these different element types can be used well together. For example:

In the spirit of the "DOM node wrappers", one could easily come up with similar wrappers around JDOM, XOM, etc., mixing in trait eu.cdevreeze.yaidom.ParentElemLike (or subtraits). Yaidom does not offer these wrappers, but some test cases show that such wrappers are easy to develop.

Examples

Below follow some examples. The first example queries for all book elements having a price below 90. It can be written as follows, assuming a book store Document with the appropriate structure:

val bookstoreElm = doc.documentElement
require(bookstoreElm.localName == "Bookstore")

val bookElms =
  for {
    bookElm <- bookstoreElm \ (_.localName == "Book")
    price <- bookElm \@ EName("Price")
    if price.toInt < 90
  } yield bookElm

The for-comprehension is equivalent to:

val bookElms =
for {
  bookElm <- bookstoreElm filterChildElems { _.localName == "Book" }
  price <- bookElm.attributeOption(EName("Price"))
  if price.toInt < 90
} yield bookElm

All books having (at least) Jeffrey Ullman as author can be found as follows:

val ullmanBookElms =
for {
  bookElm <- bookstoreElm filterChildElems { _.localName == "Book" }
  if (bookElm \\ (_.localName == "Author")) exists { e =>
    ((e.getChildElem(_.localName == "First_Name")).text == "Jeffrey") &&
    ((e.getChildElem(_.localName == "Last_Name")).text == "Ullman")
  }
} yield bookElm

An alternative way to write the same query, but using eu.cdevreeze.yaidom.ElemPath instances instead, is as follows:

val ullmanBookElms =
for {
  authorPath <- bookstoreElm filterElemPaths { e =>
    (e.localName == "Author") &&
    ((e.getChildElem(_.localName == "First_Name")).text == "Jeffrey") &&
    ((e.getChildElem(_.localName == "Last_Name")).text == "Ullman")
  }
  bookPath <- authorPath findAncestorPath { _.endsWithName(EName("Book")) }
} yield bookstoreElm.getWithElemPath(bookPath)

This is conceptually similar to navigating in XPath to the grandparent nodes of the matching Author elements.

Alternatively, using eu.cdevreeze.yaidom.indexed.Elem instances, we could write:

val ullmanBookElms =
for {
  authorElm <- indexed.Elem(bookstoreElm) filterElems { e =>
    (e.localName == "Author") &&
    ((e.getChildElem(_.localName == "First_Name")).text == "Jeffrey") &&
    ((e.getChildElem(_.localName == "Last_Name")).text == "Ullman")
  }
  bookElm <- authorElm findAncestor { _.resolvedName == EName("Book") }
} yield bookElm

What's in the API, and what are the dependencies?

This package contains the following parts, in order of dependencies (starting with the class without any dependencies):

Dependencies are all uni-directional. All types in this package are (deeply) immutable. That holds even for the eu.cdevreeze.yaidom.NodeBuilder instances.

Parsing and printing of XML are not handled in this package. Even the toString methods for nodes use the NodeBuilder DSL syntax rather than XML string syntax. Hence the complex details of character escaping, "ignorable whitespace" etc. are not handled in this package. Parsing and printing of XML are offered by the eu.cdevreeze.yaidom.parse and eu.cdevreeze.yaidom.print subpackages, which depend on the eu.cdevreeze.yaidom.convert subpackage. Those subpackages depend on this package, and not the other way around. Put differently, they are in this namespace.

Yaidom also offers packages eu.cdevreeze.yaidom.resolved, eu.cdevreeze.yaidom.indexed and eu.cdevreeze.yaidom.xlink. The resolved package offers "bare bones" elements, stripped down to "essentials" (replacing prefixes by namespace URIs, removing comments, etc.), such that those elements can be compared for some notion of equality. The indexed package offers immutable elements knowing their ancestry. The xlink package offers some basic XLink support.

There is also a package eu.cdevreeze.yaidom.dom for ElemLike wrappers around (mutable!) DOM elements.

Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By inheritance
Inherited
  1. yaidom
  2. AnyRef
  3. Any
  1. Hide All
  2. Show all
Learn more about member selection
Visibility
  1. Public
  2. All

Type Members

  1. final case class Comment(text: String) extends Node with Product with Serializable

    Annotations
    @SerialVersionUID( 1L )
  2. final case class CommentBuilder(text: String) extends NodeBuilder with Product with Serializable

    Annotations
    @SerialVersionUID( 1L )
  3. trait ConverterToDocument[A] extends AnyRef

    Converter from A (which can be anything) to eu.cdevreeze.yaidom.Document.

  4. trait ConverterToElem[A] extends AnyRef

    Converter from A (which can be anything) to eu.cdevreeze.yaidom.Elem.

  5. final case class Declarations(map: Map[String, String]) extends Immutable with Product with Serializable

    Namespace declarations (and undeclarations), typically at the level of one element.

  6. final class DocBuilder extends Immutable with Serializable

    Builder of a yaidom Document.

  7. final class Document extends Immutable with Serializable

    Document.

  8. trait DocumentConverter[A] extends AnyRef

    Converter from eu.cdevreeze.yaidom.Document to A (which can be anything, such as a DOM Document).

  9. final case class EName(namespaceUriOption: Option[String], localPart: String) extends Immutable with Product with Serializable

    Expanded name.

  10. final class Elem extends Node with UpdatableElemLike[Node, Elem] with HasText

    Element node.

  11. trait ElemApi[E <: ElemApi[E]] extends ParentElemApi[E]

    API for elements as containers of elements, each having a name and possible attributes.

  12. final class ElemBuilder extends NodeBuilder with ParentElemLike[ElemBuilder]

    Builder for elements.

  13. trait ElemConverter[A] extends AnyRef

    Converter from eu.cdevreeze.yaidom.Elem to A (which can be anything, such as a DOM Element).

  14. trait ElemLike[E <: ElemLike[E]] extends ParentElemLike[E] with ElemApi[E]

    API and implementation trait for elements as containers of elements, each having a name and possible attributes.

  15. final class ElemPath extends Immutable

    Unique identification of a descendant (or self) Elem given a root Elem.

  16. final class ElemPathBuilder extends Immutable

    Builder for ElemPath instances.

  17. final case class EntityRef(entity: String) extends Node with Product with Serializable

    An entity reference.

  18. final case class EntityRefBuilder(entity: String) extends NodeBuilder with Product with Serializable

    Annotations
    @SerialVersionUID( 1L )
  19. trait HasParent[E <: HasParent[E]] extends AnyRef

    API and implementation trait for elements that can be asked for the ancestor elements, if any.

  20. trait HasText extends AnyRef

    Trait defining the contract for elements as text containers.

  21. sealed trait Node extends Immutable with Serializable

    Immutable XML node.

  22. sealed trait NodeBuilder extends Immutable with Serializable

    DSL to build Elems (or Documents) without having to pass parent Scopes around.

  23. trait ParentElemApi[E <: ParentElemApi[E]] extends AnyRef

    API for elements as containers of elements, as element nodes in a node tree.

  24. trait ParentElemLike[E <: ParentElemLike[E]] extends ParentElemApi[E]

    API and implementation trait for elements as containers of elements, as element nodes in a node tree.

  25. trait PathAwareElemApi[E <: PathAwareElemApi[E]] extends ElemApi[E]

    API for elements as containers of elements, each having a name and possible attributes, as well as an "element path" from the root element.

  26. trait PathAwareElemLike[E <: PathAwareElemLike[E]] extends ElemLike[E] with PathAwareElemApi[E]

    API and implementation trait for elements as containers of elements, each having a name and possible attributes, as well as an "element path" from the root element.

  27. final case class PrefixedName(prefix: String, localPart: String) extends QName with Product with Serializable

  28. final case class ProcessingInstruction(target: String, data: String) extends Node with Product with Serializable

    Annotations
    @SerialVersionUID( 1L )
  29. final case class ProcessingInstructionBuilder(target: String, data: String) extends NodeBuilder with Product with Serializable

    Annotations
    @SerialVersionUID( 1L )
  30. sealed trait QName extends Immutable with Serializable

    Qualified name.

  31. final case class Scope(map: Map[String, String]) extends Immutable with Product with Serializable

    Scope mapping prefixes to namespace URIs, as well as holding an optional default namespace.

  32. final case class Text(text: String, isCData: Boolean) extends Node with Product with Serializable

    Annotations
    @SerialVersionUID( 1L )
  33. final case class TextBuilder(text: String, isCData: Boolean) extends NodeBuilder with Product with Serializable

    Annotations
    @SerialVersionUID( 1L )
  34. final case class UnprefixedName(localPart: String) extends QName with Product with Serializable

  35. trait UpdatableElemApi[N, E <: N with UpdatableElemApi[N, E]] extends PathAwareElemApi[E]

    "Updatable" element.

  36. trait UpdatableElemLike[N, E <: N with UpdatableElemLike[N, E]] extends PathAwareElemLike[E] with UpdatableElemApi[N, E]

    "Updatable" element.

Value Members

  1. object Declarations extends Serializable

  2. object DocBuilder extends Serializable

  3. object Document extends Serializable

  4. object EName extends Serializable

  5. object Elem extends Serializable

  6. object ElemPath

  7. object ElemPathBuilder

  8. object Node extends Serializable

    This singleton object contains a DSL to easily create deeply nested Elems.

  9. object NodeBuilder extends Serializable

  10. object QName extends Serializable

  11. object Scope extends Serializable

  12. object TreeReprParsers extends JavaTokenParsers

    Generator for parsers of "tree representation" expressions.

  13. package convert

    Support for conversions from/to yaidom.

  14. package dom

    Wrapper around class org.w3c.dom.Element, adapting it to the eu.cdevreeze.yaidom.ElemLike API.

  15. package indexed

    This package contains element representations that contain the "context" of the element.

  16. package parse

    Support for parsing XML into yaidom Documents and Elems.

  17. package print

    Support for "printing" yaidom Documents and Elems.

  18. package resolved

    This package contains element representations that can be compared for (some notion of "value") equality, unlike normal yaidom nodes.

  19. package xlink

    XLinks, wrapping an eu.cdevreeze.yaidom.Elem.

Inherited from AnyRef

Inherited from Any

Ungrouped