XmlPath

XPath support

Provides support for common XPath axis and filtering functions, via a native-D interface instead of typical interpreted notation.

The general idea here is to generate a NodeSet consisting of those tree-nodes which satisfy a filtering function. The direction, or axis, of tree traversal is governed by one of several predefined operations. All methods facilitiate call-chaining, where each step returns a new NodeSet instance to be operated upon.

The set of nodes themselves are collected in a freelist, avoiding heap-activity and making good use of D array-slicing facilities.

XPath examples

auto doc = new Document!(char);

// attach an element with some attributes, plus
// a child element with an attached data value
doc.tree.element   (null, "element")
        .attribute (null, "attrib1", "value")
        .attribute (null, "attrib2")
        .element   (null, "child", "value");

// select named-elements
auto set = doc.query["element"]["child"];

// select all attributes named "attrib1"
set = doc.query.descendant.attribute("attrib1");

// select elements with one parent and a matching text value
set = doc.query[].filter((doc.Node n) {return n.children.hasData("value");});

Note that path queries are temporal - they do not retain content across mulitple queries. That is, the lifetime of a query result is limited unless you explicitly copy it. For example, this will fail to operate as one might expect

auto elements = doc.query["element"];
auto children = elements["child"];

The above will lose elements, because the associated document reuses node space for subsequent queries. In order to retain results, do this

auto elements = doc.query["element"].dup;
auto children = elements["child"];

The above .dup is generally very small (a set of pointers only). On the other hand, recursive queries are fully supported

set = doc.query[].filter((doc.Node n) {return n.query[].count > 1;});

Typical usage tends to exhibit the following pattern, Where each query result is processed before another is initiated

foreach (node; doc.query.child("element"))
        {
        // do something with each node
        }

Supported axis include:

.child                  immediate children
.parent                 immediate parent
.next                   following siblings
.prev                   prior siblings
.ancestor               all parents
.descendant             all descendants
.data                   text children
.cdata                  cdata children
.attribute              attribute children

Each of the above accept an optional string, which is used in an axis-specific way to filter nodes. For instance, a .child("food") will filter <food> child elements. These variants are shortcuts to using a filter to post-process a result. Each of the above also have variants which accept a delegate instead.

In general, you traverse an axis and operate upon the results. The operation applied may be another axis traversal, or a filtering step. All steps can be, and generally should be chained together. Filters are implemented via a delegate mechanism

.filter (bool delegate(Node))

Where the delegate returns true if the node passes the filter. An example might be selecting all nodes with a specific attribute

auto set = doc.query.descendant.filter (
            (doc.Node n){return n.attributes.hasName (null, "test");}
           );

Obviously this is not as clean and tidy as true XPath notation, but that can be wrapped atop this API instead. The benefit here is one of raw throughput - important for some applications.

Note that every operation returns a discrete result. Methods first() and last() also return a set of one or zero elements. Some language specific extensions are provided for too

* .child() can be substituted with [] notation instead

* [] notation can be used to index a specific element, like .nth()

* the .nodes attribute exposes an underlying Node[], which may be
  sliced or traversed in the usual D manner

Other (query result) utility methods include

.dup
.first
.last
.opIndex
.nth
.count
.opApply

XmlPath itself needs to be a class in order to avoid forward-ref issues.

Members

Aliases

Doc
alias Doc = Document!(T)
Undocumented in source.
Node
alias Node = Doc.Node
Undocumented in source.

Functions

start
NodeSet start(Node root)

Prime a query

Structs

NodeSet
struct NodeSet

This is the meat of XPath support. All of the NodeSet operators exist here, in order to enable call-chaining.

Meta