PhoenixmlDb.XSLT
XsltTransformer
Primary API for running XSLT transformations in .NET.
#XsltTransformer
Namespace: PhoenixmlDb.Xslt
Primary API for running XSLT transformations in .NET.
XsltTransformer provides a simple three-step workflow for XSLT processing: create an instance, load a stylesheet, and transform XML input. It supports XSLT 3.0 and 4.0 features including streaming, packages, higher-order functions, maps/arrays.
Invocation styles: XSLT defines three ways to start a transformation:
-
Apply templates (default) β the processor matches templates against the source document. Optionally set an initial mode with
XsltTransformer.SetInitialMode. -
Call template β invoke a named template via
XsltTransformer.SetInitialTemplate. No source document is required (passnulltoXsltTransformer.TransformAsync). -
Call function β invoke a public stylesheet function via
XsltTransformer.SetInitialFunctionandXsltTransformer.AddInitialFunctionArgument.
Thread safety: Instances are lightweight and not thread-safe. Create a new XsltTransformer for each transformation rather than sharing one across threads.
Basic usage:
var transformer = new XsltTransformer();
await transformer.LoadStylesheetAsync(myXsltString);
transformer.SetParameter("reportDate", "2025-01-15");
string result = await transformer.TransformAsync(inputXml);
Using initial-template invocation (no source document):
var transformer = new XsltTransformer();
await transformer.LoadStylesheetAsync(generatorStylesheet);
transformer.SetInitialTemplate("main");
string result = await transformer.TransformAsync(null);
#Properties
| Name | Description |
|---|---|
AllowDtdProcessing
|
Controls whether DTD processing is allowed when loading stylesheets. Default is false (DTDs are prohibited) for security.
|
HasStreamableMode
|
True when the loaded stylesheet declares at least one streamable mode (either an explicit <xsl:mode streamable="yes"/> declaration or a streamable default mode). The CLI uses this signal to auto-select the streaming transform path for file inputs β non-streamable stylesheets always run on the materialising path. Returns false if no stylesheet is loaded yet.
|
MaxResultDocuments
|
Maximum number of secondary result documents allowed per transformation. Default is 1000. Set to 0 for unlimited. |
MessageListener
|
Listener for xsl:message output. Receives the message text and a boolean indicating whether terminate="yes" was specified. When not set, messages are silently discarded.
|
MessageListenerWithLocation
|
Extended listener for xsl:message that also receives source location (line, column). Takes precedence over XsltTransformer.MessageListener when set.
|
PreloadedResources
|
Pre-fetched contents for URIs that xsl:import / xsl:include / fn:doc() would otherwise need to fetch over HTTP synchronously. Required on Blazor WebAssembly, which cannot block the calling thread; ignored on runtimes that can. Async-fetch the resources in your host code (via HttpClient with await or via JS interop) and assign before calling XsltTransformer.LoadStylesheetAsync. See XsltTransformer.PreloadedResources for a usage example.
|
ResourcePolicy
|
Optional resource security policy. When set, controls which URIs the stylesheet can access via doc(), unparsed-text(), collection(), xsl:result-document, and xsl:import/xsl:include. See ResourcePolicy.ServerDefault for a secure server configuration.
|
ResultDocumentHandler
|
Optional callback that provides a TextWriter for each secondary result document produced by xsl:result-document. When set, secondary documents are written directly to the provided writer instead of accumulating in XsltTransformer.SecondaryResultDocuments.
|
SchemaProvider
|
Schema provider for schema-aware processing. Defaults to a fresh XsdSchemaProvider with no schemas loaded; any xsl:import-schema declarations encountered while loading a stylesheet are routed to this provider via ISchemaProvider.ImportSchema.
|
SecondaryResultDocuments
|
Secondary result documents produced by xsl:result-document, keyed by the href attribute value.
|
TraceListener
|
Sets a trace listener for debugging template matching, function calls, and built-in rule invocations during transformation. |
#Methods
#AddInitialFunctionArgument(Object)
Adds a positional argument for the initial function call.
Parameters:
-
valueβ The argument value. Arguments are positional β add them in the same order as thexsl:paramdeclarations in the targetxsl:function.
Only used with call-function invocation (see
). Call this method once per function parameter, in declaration order.
#BuildTransformOptions(Boolean,PhoenixmlDb.Xslt.Engine.RawResultBox,Threading.CancellationToken)
Builds the
from the transformer's current configuration (parameters, initial-template / mode / function selection, listeners, resource policy, preloaded resources). Centralized so the four
TransformAsync
/
TransformToValueAsync
overloads stay in sync as new options are added.
#EnableXInclude(Boolean,PhoenixmlDb.Core.Xml.IXmlResourceResolver)
Enables XInclude 1.0 expansion of the principal source document. When on, any
xi:include
(
parse="xml"
) elements in the input passed to
are expanded before the document is transformed. Off by default.
Parameters:
-
allowRemoteβ Whentrue, remote (http:/https:) include targets may be fetched. Defaults tofalse(onlyfile:/relative targets resolve). -
resolverβ Optional host resolver for include targets; whennulla built-in local-file resolver honoringallowRemoteis used.
A source base URI is required so relative
href
s resolve β set it via
before transforming.
#ExtractNonNodeHeadFromSequence(PhoenixmlDb.Xdm.XdmSequence)
Returns the head item of
when it isn't an
β typically a map, array, atomic value or function-item produced by a previous transform's
parse-json
/
map:*
/
array:*
call. The caller routes node items through
instead.
#ExtractSourceFromSequence(PhoenixmlDb.Xdm.XdmSequence)
Pulls the first node item out of a sequence (to use as principal source) and the store backing the sequence's node items. Returns (null, null) for null or empty input β the transformation will run source-less.
#LoadStylesheetAsync(String,Uri,Collections.Generic.Dictionary<String,String>,Collections.Generic.Dictionary<String,Collections.Generic.List<ValueTuple<String,String>>>,PhoenixmlDb.Xslt.PackageVersionResolution)
Compiles and loads an XSLT stylesheet from its XML source text.
Parameters:
-
stylesheetXmlβ The complete XSLT stylesheet as an XML string. Must be well-formed XML with anxsl:stylesheetorxsl:transformroot element. -
baseUriβ Base URI used to resolve relative references inxsl:import,xsl:include, and thedoc()/document()functions. Ifnull, relative URIs cannot be resolved and will cause an error. -
staticParamsβ XSLT 3.0 static parameters (xsl:paramwithstatic="yes"). These are evaluated at compile time and can influence conditional compilation viaxsl:use-whenandstatic-params. Keys are parameter local names; values are string representations. -
packageCatalogβ Maps XSLT 3.0 package names to available versions and file paths, enablingxsl:use-packageto locate and load package dependencies. Each key is a package name URI; the value is a list of(Version, FilePath)tuples. -
packageVersionResolutionβ Policy for choosing among multiple package versions that satisfy anxsl:use-package/@package-versionrange. Defaults toPackageVersionResolution.Highest.
Returns: A completed task. The stylesheet is parsed synchronously.
Exceptions:
-
ArgumentNullExceptionβstylesheetXmlisnull. -
XsltExceptionβ The stylesheet contains syntax errors or invalid XSLT constructs.
#LooksLikeXml(String)
Heuristic: the result starts with a tag, suggesting XML markup.
#ParseExternalParamValue(String)
Same value-parsing heuristics as
StylesheetParser.PopulateExternalStaticParams
: recognise XPath-shaped literals, bare booleans, and numeric strings, falling through to
xs:untypedAtomic
for free-form strings. Keeps the runtime-side variable in sync with what the static-param resolver decided about the same value.
#ResolveSchemaImports(PhoenixmlDb.Xslt.Ast.XsltStylesheet,Uri)
Forwards every captured
xsl:import-schema
declaration to the registered
. Schema-location URIs are resolved against the stylesheet base URI before being handed to the provider so relative hints work.
#SetBaseOutputUri(Uri)
Sets the base output URI β where the principal result will be written (XSLT 3.0 Β§2.3).
Parameters:
-
uriβ Absolute URI of the principal output destination.
This is what
fn:current-output-uri()
reports while the principal result is being produced, and what a relative
xsl:result-document/@href
resolves against. Leave it unset when the result has no URI β writing to stdout or to a string β in which case
current-output-uri()
correctly returns the empty sequence.
#SetCollection(String,Collections.Generic.List<String>)
Registers a named collection of document file paths, making them available to the XPath
fn:collection()
function during transformation.
Parameters:
-
uriβ The collection URI that the stylesheet passes tofn:collection(). Use an empty string for the default collection (called with no arguments). -
documentPathsβ File system paths to XML documents that comprise the collection.
#SetInitialFunction(String,String)
Sets the initial function to call, using the XSLT 3.0 "call function" invocation style.
Parameters:
-
nameβ The function name. Must match a publicxsl:functiondeclared withvisibility="public"(or the default visibility in XSLT 3.0). -
namespaceUriβ The namespace URI of the function. Stylesheet functions must be in a non-null namespace.
When using call-function invocation, supply arguments via XsltTransformer.AddInitialFunctionArgument in the order declared by the function's xsl:param elements. No source document is required β pass null to XsltTransformer.TransformAsync.
#SetInitialMode(String,String)
Sets the initial mode, determining which set of templates is applied to the source document.
Parameters:
-
modeβ The mode name. Use"#unnamed"to explicitly select the unnamed (default) mode, or a specific mode name to select templates declared with thatmodeattribute. -
namespaceUriβ The namespace URI of the mode, ornullfor modes in no namespace.
Modes allow a stylesheet to define multiple sets of template rules for the same input nodes. For example, a stylesheet might have a "toc" mode for generating a table of contents and a default mode for the main output.
If no initial mode is set, the unnamed (default) mode is used. The stylesheet's xsl:stylesheet/@default-mode attribute can also influence this behavior.
#SetInitialModeSelect(String)
Sets an XPath expression to determine the initial match selection for the initial mode.
Parameters:
-
selectβ An XPath expression evaluated with the source document as context. Templates from the initial mode are applied to each item in the resulting sequence, rather than to the document root.
This corresponds to the XSLT 3.0 initial-match-selection concept. It allows you to apply templates to a computed set of nodes rather than the single root node. For example, "//chapter" would apply templates to every chapter element in the source document.
#SetInitialTemplate(String,String)
Sets the initial named template for call-template invocation.
Parameters:
-
nameβ The template name. For templates in a namespace, use either a prefixed name (e.g.,"my:main") with the namespace URI innamespaceUri, or just the local name with the namespace URI. -
namespaceUriβ The namespace URI of the template, ornullfor templates in no namespace.
When an initial template is set, the transformation begins by calling that named template rather than applying templates to the source document. This means the inputXml parameter of XsltTransformer.TransformAsync can be null β the template generates output without needing a source document.
The conventional entry-point template name is "xsl:initial-template" (in the XSLT namespace), which is the XSLT 3.0 default initial template.
#SetInitialTemplateParameter(PhoenixmlDb.Core.QName,Object)
Sets an initial template parameter, passed via
xsl:with-param
to the initial template when using call-template invocation.
Parameters:
-
nameβ The qualified name matching anxsl:paramin the initial template. -
valueβ The value to bind to the parameter.
These parameters are distinct from stylesheet-level parameters set via
. They correspond to parameters declared inside the named template specified by
.
#SetInitialTunnelParameter(PhoenixmlDb.Core.QName,Object)
Sets an initial template tunnel parameter, which propagates through the call chain without being explicitly declared at each level.
Parameters:
-
nameβ The qualified name of the tunnel parameter. -
valueβ The value to bind to the tunnel parameter.
Tunnel parameters are an XSLT 2.0+ feature that allows values to "tunnel" through intermediate template calls to deeply nested templates that declare matching
xsl:param tunnel="yes"
parameters.
#SetParameter(PhoenixmlDb.Core.QName,Object)
Sets a global stylesheet parameter whose name is NAMESPACED, preserving its typed value.
Parameters:
-
nameβ The qualified name of a top-levelxsl:param. Pass a QName rather than a string: the string overloads take a LOCAL name and have no spelling for a namespace. -
valueβ The typed value to bind, ornullfor the empty sequence.
#SetParameter(String,Object)
Sets a stylesheet parameter with a typed value, preserving its XDM type.
Parameters:
-
nameβ The local name of anxsl:paramdeclared at the top level of the stylesheet. -
valueβ The typed value to bind. .NET types are mapped to XDM types:Int32andInt64becomexs:integer,Doublebecomesxs:double,Booleanbecomesxs:boolean,Decimalbecomesxs:decimal, andStringbecomesxs:untypedAtomic. Passnullto set the parameter to an empty sequence.
Parameters must match
xsl:param
declarations in the stylesheet. If the stylesheet declares a parameter with
as="xs:integer"
and you supply a string, a type error will occur at runtime.
#SetParameter(String,String)
Sets a stylesheet parameter with a string value.
Parameters:
-
nameβ The local name of anxsl:paramdeclared at the top level of the stylesheet. -
valueβ The string value to bind. The value is supplied asxs:untypedAtomic, which means it will be automatically promoted during comparisons β for example, comparing it to anxs:doublewill succeed without an explicit cast.
If you need the parameter to carry a specific XDM type (e.g., xs:integer or xs:boolean), use the XsltTransformer.SetParameter overload with a typed .NET value such as Int32 or Boolean.
#SetSourceDocumentUri(Uri)
Sets the URI of the source document, used for
base-uri()
and
document-uri()
resolution during transformation.
Parameters:
-
uriβ The URI to associate with the source document. This does not load the document from the URI β it only sets the base URI metadata on the document node created from theinputXmlstring passed toXsltTransformer.TransformAsync.
Setting a source document URI is important when the stylesheet uses relative URIs in
doc()
or
document()
calls that should resolve relative to the source document's location rather than the stylesheet's base URI.
#SetSourceSelect(String)
Sets an XPath expression to select the initial context node from the source document.
Parameters:
-
selectβ An XPath expression evaluated against the source document. The result becomes the initial context item for the transformation. For example,"/doc"selects the document element nameddocinstead of the document root node.
By default, the initial context item is the document node (root) of the source document. Use this method when the stylesheet expects a specific element or node as its starting context rather than the root.
#TransformAsync(IO.Stream,IO.Stream,Threading.CancellationToken)
Transforms XML from a
and writes to a
. When the loaded stylesheet's initial mode is streamable, the input stream is fed directly to the streaming engine without an intervening
ReadToEndAsync
, bounding peak memory. Non-streaming stylesheets retain the original buffered path.
#TransformAsync(IO.Stream,IO.TextWriter,Threading.CancellationToken)
Streams XML from a
and writes the serialized primary result incrementally to a
. Requires the stylesheet's initial mode to be streamable; otherwise an
is thrown by the engine.
Cancellation is not transactional β content already delivered to
before cancellation cannot be retracted.
#TransformAsync(IO.Stream,Threading.CancellationToken)
Transforms XML from a
source.
#TransformAsync(IO.TextReader,IO.TextWriter,Threading.CancellationToken)
Transforms XML from a
and writes to a
.
#TransformAsync(IO.TextReader,Threading.CancellationToken)
Transforms XML from a
source.
#TransformAsync(PhoenixmlDb.Xdm.XdmSequence,Threading.CancellationToken)
Transforms an
source β pass the typed result of one transformation directly into another, without serializing through XML markup. The engine reads the sequence's backing
Store
to navigate any node items.
When source is null or empty, the transformation runs without a principal source document β appropriate for xsl:initial-template / xsl:initial-function invocation. Otherwise the first node item in the sequence becomes the principal source.
If the sequence contains node items, its XdmSequence.Store must be a compatible XdmInMemoryStore β typically a sequence produced by a previous call to XsltTransformer.TransformToSequenceAsync.
#TransformAsync(String,IO.TextWriter,Threading.CancellationToken)
Transforms XML and writes the primary result to a
.
#TransformAsync(String,Threading.CancellationToken)
Transforms an XML string using the loaded stylesheet and returns the serialized primary result document.
Parameters:
-
inputXmlβ The source XML document to transform, ornullwhen using call-template or call-function invocation that does not require a source document. Whennull, an empty placeholder document is used internally. -
ctβ Cancellation token for aborting long-running transformations. When cancelled, anOperationCanceledExceptionis thrown.
Returns: The serialized primary result document as a string. The serialization format (XML, HTML, text, JSON, or adaptive) is determined by the stylesheet's xsl:output declaration.
Exceptions:
-
InvalidOperationExceptionβ No stylesheet has been loaded. CallXsltTransformer.LoadStylesheetAsyncfirst. -
XsltExceptionβ A runtime error occurred during transformation, such as a type error, missing template, or evaluation failure. -
OperationCanceledExceptionβ Thectcancellation token was triggered.
After this method returns, any secondary outputs produced by xsl:result-document instructions are available in XsltTransformer.SecondaryResultDocuments.
#TransformToSequenceAsync(PhoenixmlDb.Xdm.XdmSequence,Threading.CancellationToken)
Transforms an
and returns the raw XDM result wrapped in another
that carries the engine's node-store, so the result can be passed directly to another
or XQuery call without serialization.
#TransformToValueAsync(String,Threading.CancellationToken)
Transforms
and returns the RAW XDM value of the transformation β the typed result (xs:boolean, xs:integer, map, array, node, β¦) preserved end-to-end, not serialized to a string and reparsed. Used by
fn:transform()
with
delivery-format='raw'
from XQuery, where the caller wants to consume the typed result directly rather than as XML markup. Currently only honored when the transformation is invoked via
(the only case where there's a single well-defined return value); template-based invocations still serialize.
Returns: The raw XDM value: a single item, an object?[] for sequences, or null for the empty sequence.
#TryParseToXdmDocument(String,PhoenixmlDb.Xslt.XdmInMemoryStore)
Parses serialized XML markup into an
registered with
. Returns null if parsing fails (the caller falls back to keeping the raw string).
#Fields
| Name | Description |
|---|---|
_typedParametersByQName
|
Global parameters supplied by QNAME rather than by local name. Separate from _typedParameters because that one is keyed by the string a caller passed and is wrapped as a no-namespace QName; there is no string spelling of a namespaced name that survives that wrapping.
|
#See also
-
XsltException