eu.cdevreeze.yaidom

simple

package simple

This package contains the default element implementation.

This package depends only on the core and queryapi packages in yaidom, but many other packages do depend on this one.

Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By inheritance
Inherited
  1. simple
  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()
  2. final case class CommentBuilder(text: String) extends NodeBuilder with Product with Serializable

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

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

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

    A

    the type of the value to convert

  4. trait ConverterToElem[A] extends AnyRef

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

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

    A

    the type of the value to convert

  5. final class DocBuilder extends DocumentApi[ElemBuilder] with Immutable with Serializable

    Builder of a yaidom Document.

    Builder of a yaidom Document. Called DocBuilder instead of DocumentBuilder, because often a JAXP DocumentBuilder is in scope too. A DocBuilder is itself not a NodeBuilder.

    A DocBuilder is constructed from an optional URI, a document element (as ElemBuilder), top-level processing instruction builders, if any, and top-level comment builders, if any.

    Annotations
    @SerialVersionUID()
  6. final class Document extends DocumentApi[Elem] with Immutable with Serializable

    Document.

    Document. Although at first sight the document root element seems to be the root node, this is not entirely true. For example, there may be comments at top level, outside the document root element.

    The document is itself not a Node. This choice has the following advantages:

    • Documents are indeed prevented (at compile-time) from occurring as "child nodes"
    • The API is cleaner. For example, (unlike "elements") document methods like toTreeRepr should not be passed a parent scope. By not considering a Document a Node, it is more visible that parent scopes are irrelevant for Documents, unlike for "elements".

    A Document is constructed from an optional URI, a document element (as Elem), top-level processing instructions, if any, and top-level comments, if any.

    Note that class Document does not have any query methods for Elem instances. In particular, the ElemApi does not apply to documents. Therefore, given a document, querying for elements (other than the document element itself) always goes via the document element.

    Annotations
    @SerialVersionUID()
  7. trait DocumentConverter[A] extends AnyRef

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

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

    A

    the result type of the conversion

  8. final class Elem extends Node with ScopedElemLike[Elem] with UpdatableElemLike[Node, Elem] with TransformableElemLike[Node, Elem]

    Immutable, thread-safe element node.

    Immutable, thread-safe element node. It is the default element implementation in yaidom. As the default element implementation among several alternative element implementations, it strikes a balance between loss-less roundtripping and composability.

    The parsers and serializers in packages eu.cdevreeze.yaidom.parse and eu.cdevreeze.yaidom.print return and take these default elements (or the corresponding Document instances), respectively.

    As for its query API, class eu.cdevreeze.yaidom.simple.Elem is among the most powerful element implementations offered by yaidom. These elements offer all of the eu.cdevreeze.yaidom.queryapi.ElemApi, eu.cdevreeze.yaidom.queryapi.UpdatableElemApi and eu.cdevreeze.yaidom.queryapi.TransformableElemApi query APIs, and more.

    See the documentation of the mixed-in query API traits for more details on the uniform query API offered by this class.

    The following example illustrates the use of the yaidom uniform query API in combination with some Elem-specific methods. In this XML scripting example the namespace prefix "xsd" is replaced by prefix "xs", including those in QName-valued attributes. The trivial XML file of this example is the following XML Schema:

    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://book" elementFormDefault="qualified">
      <xsd:element name="book">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="isbn" type="xsd:string" />
            <xsd:element name="title" type="xsd:string" />
            <xsd:element name="authors" type="xsd:string" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>

    The edit action can be performed on this schemaElem as follows, starting with some checks:

    // All descendant-or-self elements have the same Scope, mapping only prefix "xsd".
    require(schemaElem.findAllElemsOrSelf.map(_.scope).distinct == List(Scope.from("xsd" -> "http://www.w3.org/2001/XMLSchema")))
    
    // All descendant-or-self elements have a QName with prefix "xsd".
    require(schemaElem.findAllElemsOrSelf.map(_.qname.prefixOption).distinct == List(Some("xsd")))
    
    // All descendant-or-self elements have unprefixed attributes only.
    require(schemaElem.findAllElemsOrSelf.flatMap(_.attributes.toMap.keySet.map(_.prefixOption)).distinct == List(None))
    
    // All descendant-or-self elements with "type" attributes contain only QNames with prefix "xsd" in the values of those attributes.
    require(schemaElem.filterElemsOrSelf(e => (e \@ EName("type")).isDefined).forall(e => e.attributeAsQName(EName("type")).prefixOption == Some("xsd")))
    
    // Replaces prefix "xsd" by "xs" throughout the element tree, including in "type" attributes.
    val editedSchemaElem = schemaElem transformElemsOrSelf { elem =>
      val newScope = (elem.scope -- Set("xsd")) ++ Scope.from("xs" -> "http://www.w3.org/2001/XMLSchema")
      val newQName = QName("xs", elem.qname.localPart)
      val newTypeAttrOption = elem.attributeAsQNameOption(EName("type")).map(attr => QName("xs", attr.localPart).toString)
    
      elem.copy(qname = newQName, scope = newScope).plusAttributeOption(QName("type"), newTypeAttrOption)
    }

    Note that besides the uniform query API, this example uses some Elem-specific methods, such as attributeAsQName, copy and plusAttributeOption.

    Class Elem is immutable, and (should be) thread-safe. Hence, Elems do not know about their parent element, if any.

    An Elem has the following state:

    Note that namespace declarations are not considered to be attributes in Elem, just like in the rest of yaidom. Elem construction is unsuccessful if the element name and/or some attribute names cannot be resolved using the Scope of the element (ignoring the default namespace, if any, for attributes). As can be seen from the above-mentioned state, namespaces are first-class citizens.

    Elems can (relatively easily) be constructed manually in a bottom-up manner. Yet care must be taken to give the element and its descendants the correct Scope. Otherwise it is easy to introduce (prefixed) namespace undeclarations, which are not allowed in XML 1.0. The underlying issue is that functional Elem trees are created in a bottom-up manner, whereas namespace scoping works in a top-down manner. This is not a big issue in practice, since manual Elem creation is rather rare, and it is always possible to call method notUndeclaringPrefixes afterwards. An alternative method to create element trees by hand uses class eu.cdevreeze.yaidom.simple.ElemBuilder. A manually created ElemBuilder can be converted to an Elem by calling method build.

    Round-tripping (parsing and serializing) is not entirely loss-less, but (in spite of the good composability and rather small state) not much is lost. Comments, processing instructions and entity references are retained. Attribute order is retained, although according to the XML Infoset this order is irrelevant. Namespace declaration order is not necessarily retained, however. Superfluous namespace declarations are also lost. (That is because namespace declarations are not explicitly stored in Elems, but are implicit, viz. parentElem.scope.relativize(this.scope)). The short versus long form of an empty element is also not remembered.

    Equality has not been defined for class Elem (that is, it is reference equality). There is no clear sensible notion of equality for XML trees at the abstraction level of Elem. For example, think about prefixes, "ignorable whitespace", DTDs and XSDs, etc.

    Annotations
    @SerialVersionUID()
  9. final class ElemBuilder extends NodeBuilder with ElemLike[ElemBuilder] with TransformableElemLike[NodeBuilder, ElemBuilder] with HasQNameApi with HasText

    Builder for elements.

    Builder for elements. See eu.cdevreeze.yaidom.simple.NodeBuilder.

    See the documentation of the mixed-in query API trait(s) for more details on the uniform query API offered by this class.

    Annotations
    @SerialVersionUID()
  10. trait ElemConverter[A] extends AnyRef

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

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

    A

    the result type of the conversion

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

    An entity reference.

    An entity reference. For example:

    &hello;

    We obtain this entity reference as follows:

    EntityRef("hello")
    Annotations
    @SerialVersionUID()
  12. final case class EntityRefBuilder(entity: String) extends NodeBuilder with Product with Serializable

    Annotations
    @SerialVersionUID()
  13. sealed trait Node extends Immutable with Serializable

    Immutable XML Node.

    Immutable XML Node. It is the default XML node type in yaidom. There are subclasses for different types of nodes, such as elements, text nodes, comments, entity references and processing instructions. See eu.cdevreeze.yaidom.simple.Elem for the default element type in yaidom.

  14. sealed trait NodeBuilder extends Immutable with Serializable

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

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

    import NodeBuilder._
    
    elem(
      qname = QName("dbclass:Magazine"),
      attributes = Vector(QName("Month") -> "February", QName("Year") -> "2009"),
      namespaces = Declarations.from("dbclass" -> "http://www.db-class.org"),
      children = Vector(
        elem(
          qname = QName("dbclass:Title"),
          children = Vector(text("Newsweek"))))).build()

    The latter expression could also be written as follows:

    elem(
      qname = QName("dbclass:Magazine"),
      attributes = Vector(QName("Month") -> "February", QName("Year") -> "2009"),
      namespaces = Declarations.from("dbclass" -> "http://www.db-class.org"),
      children = Vector(
        textElem(QName("dbclass:Title"), "Newsweek"))).build()

    There is an impedance mismatch between XML's scoping rules (which are top-down, from root to leaves) and "functional trees" (which are built bottom-up, from leaves to root). In the context of the Anti-XML library, Daniel Spiewak explained this impedance mismatch in https://github.com/djspiewak/anti-xml/issues/78. In yaidom, however, this impedance mismatch is far less severe. Yaidom distinguishes between eu.cdevreeze.yaidom.simple.Node and eu.cdevreeze.yaidom.simple.NodeBuilder, and eu.cdevreeze.yaidom.simple.Elem and eu.cdevreeze.yaidom.simple.ElemBuilder in particular. Elems have (fixed, resolved) Scopes, but ElemBuilders do not. Using NodeBuilders, Scope determination is postponed. Only ElemBuilders can have unbound prefixes, but only Elems have (resolved) scopes. Instead of a eu.cdevreeze.yaidom.core.Scope, an ElemBuilder has a eu.cdevreeze.yaidom.core.Declarations.

    Another reason that the above-mentioned impedance mismatch is less of a problem in practice is that typically the XML trees (as NodeBuilders or directly as Nodes) are built in a top-down manner. The eu.cdevreeze.yaidom.simple.ConverterToDocuments in package eu.cdevreeze.yaidom.convert recursively build Elems in a top-down manner, possibly creating an Elem instance (for each element) twice (first without children, and finally as a copy with children added).

    When using NodeBuilders to create a Document, this Document typically contains no "ignorable whitespace". This may cause the Document not to be pretty-printed when using a (default) eu.cdevreeze.yaidom.print.DocumentPrinter to convert the Document to an XML string. See also the classes in package eu.cdevreeze.yaidom.print.

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

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

    Annotations
    @SerialVersionUID()
  17. final case class Text(text: String, isCData: Boolean) extends Node with Product with Serializable

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

    Annotations
    @SerialVersionUID()

Value Members

  1. object DocBuilder extends Serializable

  2. object Document extends Serializable

  3. object Elem extends Serializable

  4. object Node extends Serializable

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

    This singleton object contains a DSL to easily create deeply nested Elems. It looks a lot like the DSL for NodeBuilders, using the same method names (so a local import for Node singleton object members may be needed).

    There is a catch, though. When using this DSL, scopes must be passed throughout the tree. These Scopes should typically be the same (or parent element scopes should be subscopes of child element scopes), because otherwise the corresponding XML may contain a lot of namespace undeclarations.

    Another thing to watch out for is that the "tree representations" conform to the NodeBuilder DSL, not to this one.

    In summary, the NodeBuilder DSL does have the advantage over this DSL that scopes do not have to be passed around. On the other hand, this Node DSL has the advantage that exceptions due to missing scope data are thrown immediately instead of later (when calling the build method, in the case of the NodeBuilder DSL).

    For example:

    import Node._
    
    val scope = Scope.from("dbclass" -> "http://www.db-class.org")
    
    elem(
      qname = QName("dbclass:Magazine"),
      attributes = Vector(QName("Month") -> "February", QName("Year") -> "2009"),
      scope = scope,
      children = Vector(
        elem(
          qname = QName("dbclass:Title"),
          scope = scope,
          children = Vector(text("Newsweek")))))

    The latter expression could also be written as follows:

    elem(
      qname = QName("dbclass:Magazine"),
      attributes = Vector(QName("Month") -> "February", QName("Year") -> "2009"),
      scope = scope,
      children = Vector(
        textElem(QName("dbclass:Title"), scope, "Newsweek")))
  5. object NodeBuilder extends Serializable

  6. object TreeReprParsers extends JavaTokenParsers

    Generator for parsers of "tree representation" expressions.

    Generator for parsers of "tree representation" expressions. The results from successful parses are NodeBuilder and DocBuilder instances.

    The "tree representation" expressions are themselves valid Scala code!

    Note: Parsing large "tree representations" is very slow.

Inherited from AnyRef

Inherited from Any

Ungrouped