niso-xpath
Generated from crates/niso-xpath/CONTRACT.md when the site was built at 7aa23e2.
Purpose
Section titled “Purpose”XPath 1.0 as DOM’s document.evaluate() runs it, over the trees a host
lends through niso-host’s Tree, and DOM’s XPath interfaces
(XPathEvaluator, XPathExpression, XPathResult) as the host’s platform
objects. It does not resolve namespace prefixes (the caller does, as DOM’s
XPathNSResolver), and it never changes a tree.
Public surface
Section titled “Public surface”- Rust:
parse,Parsed(prefixes,resolve),Expression(evaluateagainst a contextNode<'t>of a lentTree, to aValuethat lives for that lending),Value,XNode<'t>(a node of the tree, or an element’s attribute by index),string_value,number_to_string,string_to_number,Error,MAX_DEPTH,MAX_NODES.api:register, the three interfaces’InterfaceInfos, and one function per IDL member, taking the host asCx:x_path_evaluator::new;x_path_evaluator_base::{create_ns_resolver, xpath_prefixes, xpath_compile};x_path_expression::evaluate;x_path_result::{get_result_type, get_number_value, get_string_value, get_boolean_value, get_single_node_value, get_invalid_iterator_state, get_snapshot_length, iterate_next, snapshot_item}.
- C: the generated
niso_x_path_*shims (idl/xpath.webidl), unchanged. niso-capi’s entry points (crates/niso-capi/src/xpath.rs) runapithroughniso_host::capi::callwith the document as the host, as every crate’s shim does, until step 6 generates them per crate. - IDL, glue: idl/xpath.webidl; the glue’s
createExpressionandevaluateresolve prefixes throughxpathPrefixesandxpathCompile.
Host requirements
Section titled “Host requirements”- A tree (
Cx::tree), and Attr nodes for attributes a result holds (Cx::attribute_node). - The object table: the three interfaces’ objects; a result
retains the nodes it holds and names them inheld, so the host releases them after itsfreed. - One slot, installed by
api::register(a composition installs it: for the document,niso_dom_new): the expressionxpath_prefixesparsed, whichxpath_compileuses rather than parsing it again. In a host without it, both are NotSupportedError rather than a panic. - No tasks, timers, events or script.
May assume from dependencies
Section titled “May assume from dependencies”- niso-host:
Cx(tree,attribute_node,object,new_object,retain,release,try_with), the tree’s guarantees T1-T12,PlatformObject,Registrar,ExtKey,Error,ErrorCode.
Guarantees
Section titled “Guarantees”XPath’s data model over the host’s tree: the namespace axis is always
empty, as in browsers; doctypes are not in it (neither a child nor a
sibling of anything); a CDATA section is a text node; a tree’s topmost node
is the root node when it is a document or a fragment, and whatever it is
otherwise (a detached element is an element with no parent); an element’s
attributes are attribute nodes whose parent is the element, namespace
declarations left out of the attribute axis; an element’s Attr given as the
context node is that attribute. Name tests follow HTML’s rules for HTML
elements in HTML documents: an unprefixed name matches them in the HTML
namespace, ASCII case-insensitively, and their attributes likewise. id()
looks among the descendants of the context node’s node document, for the
first element in document order with each ID (its id attribute). A
node-set is in document order. Strings are UTF-8; string-length() and
substring() count UTF-16 code units, as browsers do, and a surrogate
pair substring() cuts in half becomes U+FFFD.
The DOM interfaces: a result’s type is the one asked for, or for type 0 the
value’s own; a node-set as a number, string or boolean is its first node’s
string-value; an iterator is invalid once any tree changed after it was
made (Tree::version); a result holds the nodes it hands out, attributes as
their Attr nodes, until it goes, and an evaluation that fails while
making its result releases the nodes it had retained; errors are DOM’s (SyntaxError,
NamespaceError, TypeError, NotSupportedError for a type past 9 or a doctype
as the context node, InvalidStateError from an invalid iterator).
Checked by tests/eval.rs and tests/api.rs on FakeHost, and through the document by niso-quickjs’s tests and WPT’s domxpath directory.
Limits
Section titled “Limits”parse rejects with Error::Syntax an expression nested more than
MAX_DEPTH (1000) deep or with more than MAX_NODES (100,000) parts,
since evaluating and freeing it recurse as deep as it nests. Tree walks are
iterative, so a tree may be as deep as it likes (tests/eval.rs walks a
chain 200,000 elements deep).
Threads
Section titled “Threads”Not Send: it runs on the agent’s thread, inside one lending of the tree.
Performance and memory
Section titled “Performance and memory”An evaluation is one lending of the tree, and walks it linearly: a step
merges its context nodes’ results, already in document order, instead of
sorting their concatenation, and skips contexts whose results an earlier
one’s already hold (tests/eval.rs counts the tree calls). Each read is one
indirect call into the host, and names and values are borrowed. On a
document of about 200,000 nodes, the document as host evaluates 12
representative expressions about twice as fast (1.6 to 2.3 times across
interleaved runs) as when the core implemented
the old Tree trait for its DOM (the step’s metrics). A result costs one
allocation, plus its node list.
None of its own: tests run on niso-host’s FakeHost and its FakeTree.
Standalone use
Section titled “Standalone use”XPath over any host’s documents: host.install(niso_xpath::api::register)
for the DOM interfaces, or just parse, resolve and
cx.tree(|t| expression.evaluate(t, context)).