Node-set ordering previously recomputed both nodes' root paths on every
precedes comparison (treePath is O(depth x siblings), so sorts were
O(n log n x depth)). Add decorate-sort-undecorate helpers,
sortedByDocumentOrder() and firstInDocumentOrder(), that compute each node's
order key once, and switch the evaluator's order-and-dedup, the EXSLT set
functions, string-value coercion, and NodeFunctions' target lookup to them.
set:leading/trailing also decorate once, reusing the keys for the pivot
filter and the final sort. precedes stays for pairwise use, sharing the
key comparator (Node.ordered). Behavior unchanged, all suites green.
Closes#113
Reach full XSLT 1.0 key, numbering, and document parity:
- xsl:key declarations are compiled into an index over the source tree;
the key() function looks nodes up by key name and value.
- format-number() renders a number against a picture string (digit places,
decimal point, grouping, percent), Foundation-free.
- xsl:number generates the context node's position rendered as arabic,
alphabetic, or roman numerals.
- document() resolves an external source through an injected loader so the
transform never reaches the filesystem or network by default.
These hang off an XPath function-table injection mechanism: the evaluator
merges an engine-supplied FunctionTable, letting XSLT register current(),
key(), format-number(), and document() per evaluation.
Closes#63
Add the string functions (concat, starts-with, contains, substring-before,
substring-after, substring, string-length, normalize-space, translate), the
number functions (sum, floor, ceiling, round), and the node functions
(local-name, name, namespace-uri, id, lang), merged into the evaluation
library. All pure Swift, no Foundation: substring search is hand-rolled.
Without a DTD, id() matches an attribute named id or xml:id.
Closes#41