XSLT and XPath Conformance

How closely @tradik/xslt-processor follows the W3C XSLT 1.0 and XPath 1.0 Recommendations and the XSLTProcessor Web API: compliance tables per specification section, the supported XSLT elements and XPath functions (including extension functions), the known deviations and the test coverage.

Contents

W3C Standards Compliance

This implementation follows these W3C specifications; the exceptions are listed under Known Deviations.

Specifications Implemented

SpecificationVersionStatus
XPath 1.0W3C Recommendation, 16 November 1999Supported except the namespace:: axis
XSLT 1.0W3C Recommendation, 16 November 1999Supported except xsl:fallback instantiation
DOM Level 3 CoreW3C Recommendation, 7 April 2004Consumed, not implemented: the host DOM (browser or jsdom) is used

XSLT 1.0 Specification Compliance

SectionFeatureStatusNotes
2Stylesheet StructureSupportedxsl:stylesheet, xsl:transform elements
3Data ModelPartialRoot, element, attribute, text, processing instruction and comment nodes; namespace nodes are not exposed
5Template RulesSupportedPattern matching, priority calculation
5.1Processing ModelSupportedBuilt-in templates for all node types
5.2PatternsSupportedAll pattern syntax including predicates
5.3Defining Template RulesSupportedmatch, name, priority, mode attributes
5.4Applying Template RulesSupportedxsl:apply-templates with select, mode
5.5Conflict ResolutionSupportedImport precedence and priority ordering
6Named TemplatesSupportedxsl:call-template, xsl:with-param
7Creating Result TreeSupportedLiteral result elements, attribute value templates
7.1.2Creating ElementsSupportedxsl:element with dynamic names/namespaces
7.1.3Creating AttributesSupportedxsl:attribute with dynamic names/namespaces
7.2Creating TextSupportedxsl:value-of, xsl:text
7.3Creating PIsSupportedxsl:processing-instruction
7.4Creating CommentsSupportedxsl:comment
7.5CopyingSupportedxsl:copy, xsl:copy-of
7.6Attribute SetsSupportedxsl:attribute-set, use-attribute-sets
7.6.2Namespace AliasesSupportedxsl:namespace-alias
8RepetitionSupportedxsl:for-each
9Conditional ProcessingSupportedxsl:if, xsl:choose, xsl:when, xsl:otherwise
10SortingSupportedxsl:sort with multiple keys, data-type, order, case-order, lang (all attribute value templates). Text sorts by Unicode code point like libxslt/Chrome; lang or case-order switch to locale collation. Numbers sort with NaN first.
11Variables/ParametersSupportedxsl:variable, xsl:param, scoping rules
11.1Result Tree FragmentsSupportedRTF handling as per spec
7.7NumberingSupportedxsl:number with level, count, from, value, format, grouping; lang and letter-value are ignored
12Additional FunctionsSupporteddocument(), key(), format-number(), current(), generate-id(), system-property(), element-available(), function-available(); unparsed-entity-uri() always returns ''
12.3Number FormattingSupportedformat-number() with xsl:decimal-format
13MessagesSupportedxsl:message with terminate attribute
14ExtensionsPartialExtension functions exsl:node-set() and msxsl:node-set(); no extension elements
15FallbackPartialxsl:fallback is accepted but never instantiated
16OutputSupportedxsl:output honored by transformToString() / serializeResult()
16.1XML Output MethodSupportedXML declaration (encoding, version, standalone), omit-xml-declaration, doctype-public/doctype-system, namespace declarations, indent="yes" for element-only content
16.1CDATA SectionsSupportedcdata-section-elements, split around ]]>
16.2HTML Output MethodSupportedVoid elements as <br>, minimized boolean attributes, unescaped script/style, no re-indent inside pre/script/style/textarea
16.3Text Output MethodSupportedConcatenation of all text nodes, no escaping
16.4Disabling Output EscapingSupporteddisable-output-escaping on xsl:text and xsl:value-of

XPath 1.0 Specification Compliance

SectionFeatureStatusNotes
2.1Location StepsSupportedaxis::node-test[predicate]
2.2AxesPartial12 of 13 axes; namespace:: always returns an empty node-set
2.3Node TestsSupportedName tests, node(), text(), comment(), processing-instruction(); unprefixed names also match namespaced nodes
2.4PredicatesSupportedPosition and boolean predicates
2.5Abbreviated SyntaxSupported., .., @, //
3.1BasicsSupportedExpression evaluation
3.2Function CallsSupportedAll core functions
3.3Node-setsSupportedUnion operator |
3.4BooleansSupportedand, or, not()
3.5NumbersSupportedIEEE 754 double-precision
3.6StringsSupportedUnicode string handling
3.7Lexical StructureSupportedFull tokenization
4.1Node Set FunctionsSupportedlast(), position(), count(), id(), local-name(), namespace-uri(), name()
4.2String FunctionsSupportedstring(), concat(), starts-with(), contains(), substring-before(), substring-after(), substring(), string-length(), normalize-space(), translate()
4.3Boolean FunctionsSupportedboolean(), not(), true(), false(), lang()
4.4Number FunctionsSupportednumber(), sum(), floor(), ceiling(), round()

XPath Axes Implementation

AxisStatusDescription
childSupportedChildren of context node
descendantSupportedDescendants of context node
parentSupportedParent of context node
ancestorSupportedAncestors of context node
following-siblingSupportedFollowing siblings
preceding-siblingSupportedPreceding siblings
followingSupportedNodes after context in document order
precedingSupportedNodes before context in document order
attributeSupportedAttributes of context node
namespaceNot supportedAlways an empty node-set
selfSupportedContext node itself
descendant-or-selfSupportedContext node and descendants
ancestor-or-selfSupportedContext node and ancestors

DOM Requirements

The library does not implement the DOM; it reads the source and stylesheet through the DOM Level 3 Core interfaces of the host (Node, Document, Element, Attr, Text, CDATASection, Comment, ProcessingInstruction, DocumentFragment, NamedNodeMap, NodeList) and creates the result with document.implementation.createDocument(). Browsers and jsdom provide all of them. XML strings returned by loaders are parsed with the global DOMParser.

Web API Compliance

This implementation provides full compatibility with the MDN XSLTProcessor API:

MethodStatusNotes
importStylesheet(node)SupportedAccepts Document or Element
transformToFragment(source, output)SupportedReturns DocumentFragment
transformToDocument(source)SupportedReturns XMLDocument
transformToString(source)ExtensionNot part of the W3C API; returns the xsl:output serialized result
setParameter(namespaceURI, localName, value)SupportedFull namespace support
getParameter(namespaceURI, localName)SupportedReturns parameter value
removeParameter(namespaceURI, localName)SupportedRemoves single parameter
clearParameters()SupportedRemoves all parameters
reset()SupportedResets processor state
setStylesheetLoader(loader)ExtensionResolves xsl:import/xsl:include
setDocumentLoader(loader)ExtensionResolves document()

XSLT Elements Supported

ElementStatus
xsl:apply-templatesSupported
xsl:attributeSupported
xsl:call-templateSupported
xsl:choose / when / otherwiseSupported
xsl:commentSupported
xsl:copySupported
xsl:copy-ofSupported
xsl:elementSupported
xsl:for-eachSupported
xsl:ifSupported
xsl:messageSupported
xsl:numberSupported (lang and letter-value are ignored; decimal tokens in any Unicode digit family)
xsl:outputSupported
xsl:paramSupported
xsl:processing-instructionSupported
xsl:sortSupported
xsl:templateSupported
xsl:textSupported
xsl:value-ofSupported
xsl:variableSupported
xsl:with-paramSupported
xsl:importSupported
xsl:includeSupported
xsl:apply-importsSupported
xsl:attribute-setSupported (also via xsl:use-attribute-sets on literal result elements)
xsl:keySupported (see key())
xsl:decimal-formatSupported (see format-number())
xsl:namespace-aliasSupported
xsl:strip-space / xsl:preserve-spaceSupported
xsl:fallbackSupported: used for unknown XSLT instructions and extension elements; an extension element without a fallback or a registered implementation outputs nothing (with a warning)

XPath Functions Supported

Node Set Functions

  • count(), id(), last(), local-name(), name(), namespace-uri(), position()

String Functions

  • concat(), contains(), normalize-space(), starts-with(), string(), string-length(), substring(), substring-after(), substring-before(), translate()

Boolean Functions

  • boolean(), false(), lang(), not(), true()

Number Functions

  • ceiling(), floor(), number(), round(), sum()

XSLT-Defined Functions

  • current() - the XSLT current node, also inside predicates
  • document(object, base?) - external documents, see setDocumentLoader()
  • element-available(name), function-available(name) - reflect the real element and function tables
  • format-number(number, pattern, decimalFormat?) - full XSLT 1.0 picture strings, honouring xsl:decimal-format
  • generate-id(nodeSet?) - stable identifier for the life of the transformation
  • key(name, value) - xsl:key lookup, with lazily built per-document indexes
  • system-property(name) - xsl:version, xsl:vendor, xsl:vendor-url
  • unparsed-entity-uri(name) - always returns '' (unparsed entities are not exposed by the DOM)

Extension Functions (EXSLT)

The EXSLT functions that libexslt (bundled with libxslt, used by Chrome's native XSLTProcessor) provides are implemented with libexslt's behaviour. Bind any prefix to the module namespace; function-available() reports each function.

ModuleNamespaceFunctions
Commonhttp://exslt.org/commonnode-set, object-type (also msxsl:node-set in urn:schemas-microsoft-com:xslt)
Mathhttp://exslt.org/mathmin, max, highest, lowest, abs, sqrt, power, constant, log, random, sin, cos, tan, asin, acos, atan, atan2, exp
Setshttp://exslt.org/setsdifference, intersection, distinct, has-same-node, leading, trailing
Stringshttp://exslt.org/stringstokenize, split, replace, padding, align, concat, encode-uri, decode-uri
Dates and timeshttp://exslt.org/dates-and-timesdate-time, date, time, year, leap-year, month-in-year, month-name, month-abbreviation, week-in-year, week-in-month, day-in-year, day-in-month, day-of-week-in-month, day-in-week, day-name, day-abbreviation, hour-in-day, minute-in-hour, second-in-minute, seconds, add, add-duration, difference, duration, sum
Dynamichttp://exslt.org/dynamicevaluate (opt-in, see below)

Not supported, as in libexslt: date:format-date, date:parse-date, dyn:map and the exsl:document element; calling them throws Unknown function.

  • Current-time functions use the local time zone. For reproducible output set SOURCE_DATE_EPOCH (seconds, UTC) or processor.engine.clock = () => new Date(...).
  • dyn:evaluate() evaluates XPath built from strings, which often come from the transformed data. It is disabled by default (function-available('dyn:evaluate') is false); enable it only for trusted input with processor.engine.enableDynamicEvaluate = true after importStylesheet().
  • Lengths and positions count Unicode characters, where libexslt counts bytes.

Conformance Notes

  • CDATA sections count as text everywhere (string-value, text(), xsl:value-of, xsl:copy-of); a run of adjacent text and CDATA nodes is a single text node
  • Patterns (match, count, from, xsl:key) support every XSLT 1.0 form, including multi-step paths, //, positional predicates, id() and key(), and are matched in time proportional to the node's depth
  • Template conflicts with equal priority and import precedence resolve to the last template, like libxslt
  • Without xsl:output method, a result whose root element is <html> is serialized as HTML
  • XML whitespace means space, tab, CR and LF only; a non-breaking space is ordinary text
  • The identity transform <xsl:template match="@*|node()"><xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy></xsl:template> round-trips a document exactly
  • xsl:number supports level="single|multiple|any" with count, from, grouping-separator/grouping-size, the 1, 01, a, A, i, I format tokens and decimal tokens of any Unicode digit family
  • Unprefixed name tests (item, @a) match only nodes in no namespace (XPath 1.0 section 2.3); in HTML documents element names are matched case-insensitively regardless of namespace, as browsers do
  • The namespace:: axis returns a namespace node for every binding in scope, including xml
  • transformToFragment() into an HTML document parses html output as HTML, like Chrome, so the fragment contains real HTMLElements
  • The result tree is built in a neutral XML document and imported into the output document at the end, so element names and namespaces survive an HTML owner document

Known Deviations

Differences from the XSLT 1.0 / XPath 1.0 specifications and from libxslt (the engine behind Chrome's native XSLTProcessor):

  • Recursion depth: like libxslt, a transformation may nest up to 3,000 template instantiations, built-in template rules included; deeper recursion stops with Template recursion too deep. Raise the limit with new XSLTProcessor({ maxTemplateDepth: 10000 }). libxslt also counts the content of xsl:if, xsl:choose and xsl:for-each, so this engine allows somewhat deeper recursion.
  • xsl:number: lang and letter-value are ignored. Decimal format tokens in any Unicode digit family work; negative values are numbered 0 with a warning, as in libxslt.
  • unparsed-entity-uri() always returns '' because the DOM does not expose unparsed entities.
  • HTML URI attributes are %-escaped like libxml2 (href, action, src and a/@name: spaces, control characters and non-ASCII), not the full HTML 4 URI attribute list.
  • Empty XHTML elements are written as <br /> and <a></a>, as the DOM serializers of Chrome and Firefox do, where libxml2 writes <br/> and <a/>.
  • Number to string conversion follows XPath 1.0 section 4.2 (shortest round-trip form, no exponent): string(10000000000) is 10000000000, while libxml2 rounds to 15 significant digits and uses exponents (1e+10), as Chrome does. Firefox follows the specification.
  • xsl:exclude-result-prefixes on a literal result element also excludes namespaces inherited from the template (XSLT 1.0 section 7.1.1, Firefox); libxslt ignores it for inherited namespaces.
  • legacyNameTests (deprecated, to be removed in a future major release): new XSLTProcessor({ legacyNameTests: true }) restores the pre-1.2.0 matching where unprefixed name tests also selected namespaced nodes.

Test Coverage

npm test runs 1,496 tests with Node's built-in test runner (100% line and function coverage, 98% branch coverage for 1.2.0):

AreaTest files
XSLTProcessor API and serializationsrc/XSLTProcessor*.test.js, src/index.test.js
XPath tokenizer, evaluator, axes, conformancesrc/xpath/*.test.js
XSLT engine, patterns, templates, keys, numbering, sorting, scopingsrc/xslt/*.test.js, src/xslt/engine/*.test.js
xsl:output serializerssrc/xslt/serializer.test.js, src/xslt/outputRecovery.test.js
Command line toolsrc/cli.test.js
Reported issuessrc/regressions.test.js

Conformance test suite

npm run test:conformance runs the test corpus of libxslt 1.1.45 (MIT), the XSLT engine behind Chrome's native XSLTProcessor, against this library. The corpus is downloaded and checksum-verified on first run; known failures are listed in tests/conformance/baseline.json and CI fails only on new failures. Details: tests/conformance/README.md.

ResultCases
Passing299 of 299 counted (100%)
Skipped32 DTD-dependent, implementation-defined or extension-only cases

This page is generated from docs/CONFORMANCE.md in the repository. Corrections are welcome as a pull request to that file.