Trait/Object

eu.cdevreeze.yaidom.queryapi

ElemApi

Related Docs: object ElemApi | package queryapi

Permalink

trait ElemApi extends AnyElemApi

This is the foundation of the yaidom uniform query API. Many DOM-like element implementations in yaidom mix in this trait (indirectly, because some implementing sub-trait is mixed in), thus sharing this query API.

This trait typically does not show up in application code using yaidom, yet its (uniform) API does. Hence, it makes sense to read the documentation of this trait, knowing that the API is offered by multiple element implementations.

This trait is purely abstract. The most common implementation of this trait is eu.cdevreeze.yaidom.queryapi.ElemLike. That trait only knows about elements (and not about other nodes), and only knows that elements can have child elements (again not knowing about other child nodes). Using this minimal knowledge alone, it offers methods to query for descendant elements, descendant-or-self methods, or sub-collections thereof. It is this minimal knowledge that makes this API uniform.

This query API leverages the Scala Collections API. Query results can be manipulated using the Collections API, and the query API implementation (in ElemLike) uses the Collections API internally.

ElemApi examples

To illustrate usage of this API, consider the following example. Let's say we want to determine if some XML has its namespace declarations (if any) only at the root element level. We show the query code for several yaidom DOM-like element implementations.

Note that it depends on the DOM-like element implementation how to query for namespace declarations, but the code to query for descendant or descendant-or-self elements remains the same. The method to retrieve all descendant elements is called findAllElems, and the method to retrieve all descendant-or-self elements is called findAllElemsOrSelf. The corresponding "filtering" methods are called filterElems and filterElemsOrSelf, respectively. Knowing this, it is easy to guess the other API method names.

Let's start with a yaidom DOM wrapper, named rootElem, of type DomElem, and query for the "offending" descendant elements:

rootElem filterElems (elem => !convert.DomConversions.extractNamespaceDeclarations(elem.wrappedNode.getAttributes).isEmpty)

This returns all offending elements, that is, all descendant elements of the root element (excluding the root element itself) that have at least one namespace declaration.

Now let's use an eu.cdevreeze.yaidom.simple.ElemBuilder, again named rootElem:

rootElem filterElems (elem => !elem.namespaces.isEmpty)

The query is the same as the preceding one, except for the retrieval of namespace declarations of an element. (It should be noted that class ElemBuilder already has a method allDeclarationsAreAtTopLevel.)

Finally, let's use a rootElem of type eu.cdevreeze.yaidom.indexed.Elem, which is immutable, but knows its ancestry:

rootElem filterElems (elem => !elem.namespaces.isEmpty)

This is exactly the same code as for ElemBuilder, because namespace declarations happen to be retrieved in the same way.

If we want to query for all elements with namespace declarations, including the root element itself, we could write:

rootElem filterElemsOrSelf (elem => !elem.namespaces.isEmpty)

In summary, the extremely simple ElemApi query API is indeed a uniform query API, offered by many different yaidom DOM-like element implementations.

ElemApi more formally

In order to get started using the API, this more formal section can safely be skipped. On the other hand, this section may provide a deeper understanding of the API.

The ElemApi trait can be understood in a precise mathematical sense, as shown below.

The most fundamental method of this trait is findAllChildElems. The semantics of the other methods can be defined directly or indirectly in terms of this method.

The basic operations definable in terms of that method are \ (alias for filterChildElems), \\ (alias for filterElemsOrSelf) and \\! (alias for findTopmostElemsOrSelf). Their semantics must be as if they had been defined as follows:

def filterChildElems(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
  this.findAllChildElems.filter(p)

def filterElemsOrSelf(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
  Vector(this).filter(p) ++ (this.findAllChildElems flatMap (_.filterElemsOrSelf(p)))

def findTopmostElemsOrSelf(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
  if (p(this)) Vector(this)
  else (this.findAllChildElems flatMap (_.findTopmostElemsOrSelf(p)))

Moreover, we could have defined:

def filterElems(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
  this.findAllChildElems flatMap (_.filterElemsOrSelf(p))

def findTopmostElems(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
  this.findAllChildElems flatMap (_.findTopmostElemsOrSelf(p))

and:

def findAllElemsOrSelf: immutable.IndexedSeq[ThisElem] = filterElemsOrSelf(e => true)

def findAllElems: immutable.IndexedSeq[ThisElem] = filterElems(e => true)

The following properties must hold (in the absence of side-effects), and can indeed be proven (given the documented "definitions" of these operations):

// Filtering

elem.filterElems(p) == elem.findAllElems.filter(p)

elem.filterElemsOrSelf(p) == elem.findAllElemsOrSelf.filter(p)

// Finding topmost

elem.findTopmostElems(p) == {
  elem.filterElems(p) filter { e =>
    val hasNoMatchingAncestor = elem.filterElems(p) forall { _.findElem(_ == e).isEmpty }
    hasNoMatchingAncestor
  }
}

elem.findTopmostElemsOrSelf(p) == {
  elem.filterElemsOrSelf(p) filter { e =>
    val hasNoMatchingAncestor = elem.filterElemsOrSelf(p) forall { _.findElem(_ == e).isEmpty }
    hasNoMatchingAncestor
  }
}

(elem.findTopmostElems(p) flatMap (_.filterElemsOrSelf(p))) == (elem.filterElems(p))

(elem.findTopmostElemsOrSelf(p) flatMap (_.filterElemsOrSelf(p))) == (elem.filterElemsOrSelf(p))
Linear Supertypes
AnyElemApi, AnyRef, Any
Known Subclasses
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. ElemApi
  2. AnyElemApi
  3. AnyRef
  4. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. All

Type Members

  1. abstract type ThisElem <: ElemApi

    Permalink

    The element type itself.

    The element type itself. It must be restricted to a sub-type of the query API trait in question.

    Concrete element classes will restrict this type to that element class itself.

    Definition Classes
    ElemApiAnyElemApi

Abstract Value Members

  1. abstract def \(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Shorthand for filterChildElems(p).

    Shorthand for filterChildElems(p). Use this shorthand only if the predicate is a short expression.

  2. abstract def \\(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Shorthand for filterElemsOrSelf(p).

    Shorthand for filterElemsOrSelf(p). Use this shorthand only if the predicate is a short expression.

  3. abstract def \\!(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Shorthand for findTopmostElemsOrSelf(p).

    Shorthand for findTopmostElemsOrSelf(p). Use this shorthand only if the predicate is a short expression.

  4. abstract def filterChildElems(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Returns the child elements obeying the given predicate.

    Returns the child elements obeying the given predicate. This method could be defined as:

    def filterChildElems(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
      this.findAllChildElems.filter(p)
  5. abstract def filterElems(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Returns the descendant elements obeying the given predicate, in document order.

    Returns the descendant elements obeying the given predicate, in document order. This method could be defined as:

    this.findAllChildElems flatMap (_.filterElemsOrSelf(p))
  6. abstract def filterElemsOrSelf(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Returns the descendant-or-self elements obeying the given predicate, in document order.

    Returns the descendant-or-self elements obeying the given predicate, in document order. This method could be defined as:

    def filterElemsOrSelf(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
      Vector(this).filter(p) ++ (this.findAllChildElems flatMap (_.filterElemsOrSelf(p)))

    It can be proven that the result is equivalent to findAllElemsOrSelf filter p.

  7. abstract def findAllChildElems: IndexedSeq[ThisElem]

    Permalink

    Core method that returns all child elements, in the correct order.

    Core method that returns all child elements, in the correct order. Other operations can be defined in terms of this one.

  8. abstract def findAllElems: IndexedSeq[ThisElem]

    Permalink

    Returns all descendant elements (not including this element), in document order.

    Returns all descendant elements (not including this element), in document order. This method could be defined as filterElems { e => true }. Equivalent to findAllElemsOrSelf.drop(1).

  9. abstract def findAllElemsOrSelf: IndexedSeq[ThisElem]

    Permalink

    Returns this element followed by all descendant elements (that is, the descendant-or-self elements), in document order.

    Returns this element followed by all descendant elements (that is, the descendant-or-self elements), in document order. This method could be defined as filterElemsOrSelf { e => true }.

  10. abstract def findChildElem(p: (ThisElem) ⇒ Boolean): Option[ThisElem]

    Permalink

    Returns the first found child element obeying the given predicate, if any, wrapped in an Option.

    Returns the first found child element obeying the given predicate, if any, wrapped in an Option. This method could be defined as filterChildElems(p).headOption.

  11. abstract def findElem(p: (ThisElem) ⇒ Boolean): Option[ThisElem]

    Permalink

    Returns the first found (topmost) descendant element obeying the given predicate, if any, wrapped in an Option.

    Returns the first found (topmost) descendant element obeying the given predicate, if any, wrapped in an Option. This method could be defined as filterElems(p).headOption.

  12. abstract def findElemOrSelf(p: (ThisElem) ⇒ Boolean): Option[ThisElem]

    Permalink

    Returns the first found (topmost) descendant-or-self element obeying the given predicate, if any, wrapped in an Option.

    Returns the first found (topmost) descendant-or-self element obeying the given predicate, if any, wrapped in an Option. This method could be defined as filterElemsOrSelf(p).headOption.

  13. abstract def findTopmostElems(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Returns the descendant elements obeying the given predicate that have no ancestor obeying the predicate.

    Returns the descendant elements obeying the given predicate that have no ancestor obeying the predicate. This method could be defined as:

    this.findAllChildElems flatMap (_.findTopmostElemsOrSelf(p))
  14. abstract def findTopmostElemsOrSelf(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]

    Permalink

    Returns the descendant-or-self elements obeying the given predicate, such that no ancestor obeys the predicate.

    Returns the descendant-or-self elements obeying the given predicate, such that no ancestor obeys the predicate. This method could be defined as:

    def findTopmostElemsOrSelf(p: ThisElem => Boolean): immutable.IndexedSeq[ThisElem] =
      if (p(this)) Vector(this)
      else (this.findAllChildElems flatMap (_.findTopmostElemsOrSelf(p)))
  15. abstract def getChildElem(p: (ThisElem) ⇒ Boolean): ThisElem

    Permalink

    Returns the single child element obeying the given predicate, and throws an exception otherwise.

    Returns the single child element obeying the given predicate, and throws an exception otherwise. This method could be defined as findChildElem(p).get.

  16. abstract def thisElem: ThisElem

    Permalink

    This element itself.

    This element itself.

    Definition Classes
    AnyElemApi

Concrete Value Members

  1. final def !=(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  2. final def ##(): Int

    Permalink
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  4. final def asInstanceOf[T0]: T0

    Permalink
    Definition Classes
    Any
  5. def clone(): AnyRef

    Permalink
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  6. final def eq(arg0: AnyRef): Boolean

    Permalink
    Definition Classes
    AnyRef
  7. def equals(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  8. def finalize(): Unit

    Permalink
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( classOf[java.lang.Throwable] )
  9. final def getClass(): Class[_]

    Permalink
    Definition Classes
    AnyRef → Any
  10. def hashCode(): Int

    Permalink
    Definition Classes
    AnyRef → Any
  11. final def isInstanceOf[T0]: Boolean

    Permalink
    Definition Classes
    Any
  12. final def ne(arg0: AnyRef): Boolean

    Permalink
    Definition Classes
    AnyRef
  13. final def notify(): Unit

    Permalink
    Definition Classes
    AnyRef
  14. final def notifyAll(): Unit

    Permalink
    Definition Classes
    AnyRef
  15. final def synchronized[T0](arg0: ⇒ T0): T0

    Permalink
    Definition Classes
    AnyRef
  16. def toString(): String

    Permalink
    Definition Classes
    AnyRef → Any
  17. final def wait(): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  18. final def wait(arg0: Long, arg1: Int): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  19. final def wait(arg0: Long): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )

Inherited from AnyElemApi

Inherited from AnyRef

Inherited from Any

Ungrouped