Document
, containing an "indexed" document element.
Document
, containing an "indexed" document element.
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.
An element within its context.
An element within its context. In other words, an element as a pair containing the root element (as eu.cdevreeze.yaidom.simple.Elem) and a path (from that root element) to this element.
See the documentation of the mixed-in query API trait(s) for more details on the uniform query API offered by this class.
An indexed.Elem(rootElem)
can be seen as one immutable snapshot of an XML tree. All queries (using the ElemApi
uniform
query API) on that snapshot return results within the same snapshot. Take care not to mix up query results from different
snapshots. (This could have been modeled in an alternative design of the class, using a member type, but such a design has
not been chosen.)
Below follows an example. This example queries for all book elements having at least Jeffrey Ullman as author. It can be written as follows,
assuming a book store Document
with the appropriate structure:
val bookstoreElm = indexed.Document(doc).documentElement require(bookstoreElm.localName == "Bookstore") val ullmanBookElms = for { authorElm <- bookstoreElm filterElems { e => (e.localName == "Author") && ((e.getChildElem(_.localName == "First_Name")).text == "Jeffrey") && ((e.getChildElem(_.localName == "Last_Name")).text == "Ullman") } bookElm <- authorElm.path findAncestorPath { _.elementNameOption == Some(EName("Book")) } map { path => bookstoreElm.getElemOrSelfByPath(path) } } yield bookElm
Note how we found an ancestor (Book) element of an Author element by first finding the appropriate ancestor path, and then querying the bookstore element for the element at that path. So we remembered the document element (as indexed element), and used that "snapshot" to navigate to elements at given ancestor paths of other elements. This is certainly more efficient than re-indexing (using an indexed element factory method).
In order to get started using the class, this more formal section can safely be skipped. On the other hand, this section may provide a deeper understanding of the class.
Let indexedRootElem
be a root element, so indexedRootElem.path == Path.Root
.
Then, first of all, we have:
indexedRootElem.elem == indexedRootElem.rootElem
Given:
val elems = indexedRootElem.findAllElemsOrSelf
the following (rather obvious) properties hold for indexed elements:
elems forall (e => e.rootElem == indexedRootElem.rootElem) elems forall { e => e.rootElem.findElemOrSelfByPath(e.path) == Some(e.elem) }
The properties above hold for findAllElemsOrSelf
, so they certainly hold for the other child/descendant/descendant-or-self
element query methods.
This package contains element representations that contain the "context" of the element. That is, the elements in this package are pairs of a root element and a path (to the actual element itself).
An example of where such a representation can be useful is XML Schema. After all, to interpret an element definition in an XML schema, we need context of the element definition to determine the target namespace, or to determine whether the element definition is top level, etc.
Below follows a simple example query, using the uniform query API:
The query for Scala book authors would have been exactly the same if normal
Elem
s had been used instead ofindexed.Elem
s (replacingindexedBookstoreElem
bybookstoreElem
)!