How Does doc() Differ from document() in XSLT 2.0?
In XSLT development, accessing external XML data transitioned
significantly between XSLT 1.0 and XSLT 2.0. While XSLT 1.0 relied
exclusively on the versatile but complex document()
function, XSLT 2.0 introduced doc() alongside
document() to provide a simpler, standardized mechanism
based on XPath 2.0 and the XML Query data model. This article breaks
down the technical differences between doc() and
document(), examining their URI resolution rules, handling
of multiple arguments, node sequencing, and error behavior.
Core Purpose and Origins
The document() function was designed specifically for
XSLT 1.0 to load external resources, process secondary XML files, and
read lookup tables. Because XPath 1.0 lacked a native mechanism for
opening external documents, document() was an XSLT-specific
instruction.
With XSLT 2.0 and XPath 2.0, the core specification integrated the
doc() function into the XPath 2.0 Functions and Operators
standard. The goal was to provide a streamlined, predictable function
for retrieving a single document, aligning XPath with XQuery.
Key Differences
1. Argument Types and Document Counts
doc($uri): Accepts a single string argument (or an empty sequence) representing a single URI. It returns exactly one document node (document-node()), or an empty sequence if the argument is an empty sequence.document($uri-sequence, [$base-node]): Accepts a node-set, sequence, or string as its first argument. If passed a node-set or sequence of URIs, it fetches all referenced XML documents and returns their document nodes merged into a single node collection.
2. Base URI Resolution
doc($uri): Resolves relative URIs against the static base URI of the stylesheet expression where the call appears. It does not accept a second argument for dynamic base URI overriding.document($uri, $base-node): Allows an optional second argument (a node). If supplied, relative URIs in the first argument resolve against the base URI of that specific node rather than the stylesheet, allowing dynamic URI resolution based on source document structure.
3. Whitespace and Node Stripping
doc(): Does not apply the stylesheet’sxsl:strip-spaceorxsl:preserve-spacedeclarations to the loaded document in standard XPath implementations unless explicitly handled by the XSLT processor's document builder settings.document(): Integrates directly into the XSLT processing model, routinely applying whitespace stripping rules defined byxsl:strip-spacein the importing stylesheet.
4. Error Handling and Missing Resources
doc(): Triggers a dynamic error (FODC0002) if the resource cannot be retrieved or contains malformed XML. To handle missing files safely, XSLT 2.0 pairs it withdoc-available($uri).document(): Historically permitted processors to return an empty node-set rather than raising a fatal error if a document was not found, depending on the XSLT 1.0 implementation.
Comparison Summary
| Feature | doc() (XPath 2.0 / XSLT 2.0) |
document() (XSLT 1.0 / 2.0) |
|---|---|---|
| Standard Origin | XPath 2.0 / XQuery 1.0 | XSLT 1.0 / XSLT 2.0 |
| Input Arguments | Single URI string (or empty) | Sequence/Node-set of URIs, optional base node |
| Return Value | Single document node or empty | Node-set of multiple document nodes |
| Base URI Default | Static base URI of stylesheet | Static base URI or dynamic node base |
| Safety Check | Use with doc-available() |
Implementation-dependent empty fallback |
When to Use Which
In modern XSLT 2.0 and 3.0 stylesheets, doc() is
preferred for loading individual external XML resources due to its
strict typing and cross-compatibility with XQuery. The
document() function remains useful when you need to load a
batch of documents simultaneously from a list of URI nodes or require
dynamic base URI resolution using a secondary context node.