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
) uses the Collections API internally.ElemLike
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
, and the method to retrieve all descendant-or-self elements is called findAllElems
.
The corresponding "filtering" methods are called findAllElemsOrSelf
and filterElems
, respectively. Knowing this,
it is easy to guess the other API method names.filterElemsOrSelf
Let's start with a yaidom DOM wrapper, named
, of type rootElem
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
already has a method ElemBuilder
.)allDeclarationsAreAtTopLevel
Finally, let's use a
of type eu.cdevreeze.yaidom.indexed.Elem, which is immutable, but knows its ancestry:rootElem
rootElem filterElems (elem => !elem.namespaces.isEmpty)
This is exactly the same code as for
, because namespace declarations happen to be retrieved in the same way.ElemBuilder
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
query API is indeed a uniform query API, offered by many different
yaidom DOM-like element implementations.ElemApi
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
trait can be understood in a precise mathematical sense, as shown below.ElemApi
The most fundamental method of this trait is
. The semantics of the other methods can be defined
directly or indirectly in terms of this method.findAllChildElems
The basic operations definable in terms of that method are
(alias for \
), filterChildElems
(alias for \\
)
and filterElemsOrSelf
(alias for \\!
). Their semantics must be as if they had been defined as follows:findTopmostElemsOrSelf
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))
- Alphabetic
- By Inheritance
- ElemApi
- AnyElemApi
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Type Members
- abstract type ThisElem <: ElemApi
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
- ElemApi → AnyElemApi
Abstract Value Members
- abstract def \(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
Shorthand for
filterChildElems(p)
.Shorthand for
filterChildElems(p)
. Use this shorthand only if the predicate is a short expression. - abstract def \\(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
Shorthand for
filterElemsOrSelf(p)
.Shorthand for
filterElemsOrSelf(p)
. Use this shorthand only if the predicate is a short expression. - abstract def \\!(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
Shorthand for
findTopmostElemsOrSelf(p)
.Shorthand for
findTopmostElemsOrSelf(p)
. Use this shorthand only if the predicate is a short expression. - abstract def filterChildElems(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
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)
- abstract def filterElems(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
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))
- abstract def filterElemsOrSelf(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
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
. - abstract def findAllChildElems: IndexedSeq[ThisElem]
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.
- abstract def findAllElems: IndexedSeq[ThisElem]
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 tofindAllElemsOrSelf.drop(1)
. - abstract def findAllElemsOrSelf: IndexedSeq[ThisElem]
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 }
. - abstract def findChildElem(p: (ThisElem) ⇒ Boolean): Option[ThisElem]
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 asfilterChildElems(p).headOption
. - abstract def findElem(p: (ThisElem) ⇒ Boolean): Option[ThisElem]
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 asfilterElems(p).headOption
. - abstract def findElemOrSelf(p: (ThisElem) ⇒ Boolean): Option[ThisElem]
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 asfilterElemsOrSelf(p).headOption
. - abstract def findTopmostElems(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
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))
- abstract def findTopmostElemsOrSelf(p: (ThisElem) ⇒ Boolean): IndexedSeq[ThisElem]
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)))
- abstract def getChildElem(p: (ThisElem) ⇒ Boolean): ThisElem
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
. - abstract def thisElem: ThisElem
This element itself.
This element itself.
- Definition Classes
- AnyElemApi
Concrete Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##(): Int
- Definition Classes
- AnyRef → Any
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def clone(): AnyRef
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @native() @throws(classOf[java.lang.CloneNotSupportedException])
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- def finalize(): Unit
- Attributes
- protected[java.lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.Throwable])
- final def getClass(): Class[_]
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @native()
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @native()
- final def synchronized[T0](arg0: ⇒ T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- AnyRef → Any
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @native() @throws(classOf[java.lang.InterruptedException])