xslt 1.6.2
See the version list below for details.
dotnet tool install --global xslt --version 1.6.2
dotnet new tool-manifest
dotnet tool install --local xslt --version 1.6.2
#tool dotnet:?package=xslt&version=1.6.2
nuke :add-package xslt --version 1.6.2
xslt
Command-line XSLT 3.0/4.0 processor for .NET. Transform XML documents from the terminal using the PhoenixmlDb XSLT engine.
Installation
dotnet tool install -g xslt
Usage
# Transform XML with a stylesheet
xslt stylesheet.xsl input.xml
# Write output to a file
xslt -o result.html report.xsl data.xml
# Start from a named template (no source needed)
xslt -it main generate.xsl
# Pass parameters
xslt -p year=2026 -p title="Report" style.xsl data.xml
# Read source from stdin
cat data.xml | xslt transform.xsl
# Show timing breakdown
xslt --timing style.xsl large-input.xml
# Validate a stylesheet without running
xslt --dry-run style.xsl
# Stream large files (lower memory)
xslt --stream style.xsl large-input.xml
Features
- XSLT 3.0/4.0 — packages, streaming, maps/arrays, higher-order functions, JSON output
- Multiple output methods — XML, HTML, XHTML, text, JSON, adaptive
- Streaming — process large files without loading into memory
- xsl:result-document — generate multiple output files in one transform
- Parameters — pass values from the command line
- Timing — built-in performance profiling
- Tracing — log template matching, function calls, and built-in rules
Documentation
Full documentation at phoenixml.dev
License
Apache-2.0
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.6.4 | 59 | 8/16/2026 |
| 1.6.3 | 60 | 8/14/2026 |
| 1.6.2 | 53 | 8/13/2026 |
| 1.6.1 | 70 | 8/4/2026 |
| 1.6.0 | 72 | 7/31/2026 |
| 1.5.0 | 73 | 7/27/2026 |
| 1.4.25 | 75 | 7/17/2026 |
| 1.4.24 | 70 | 7/14/2026 |
| 1.4.23 | 88 | 7/12/2026 |
| 1.4.22 | 82 | 7/10/2026 |
| 1.4.21 | 74 | 7/9/2026 |
| 1.4.20 | 64 | 7/9/2026 |
| 1.4.19 | 77 | 7/9/2026 |
| 1.4.18 | 70 | 7/8/2026 |
| 1.4.17 | 76 | 7/7/2026 |
| 1.4.16 | 82 | 6/30/2026 |
| 1.4.15 | 84 | 6/25/2026 |
| 1.4.14 | 90 | 6/22/2026 |
| 1.4.13 | 86 | 6/21/2026 |
| 1.4.12 | 85 | 6/19/2026 |
### Fixes
- **An `xsl:attribute` (or `xsl:namespace`) inside a typed `xsl:variable` / `xsl:param` / `xsl:with-param` body no longer raises a spurious `XTDE0420` when the construction happens inside a temporary tree.** An `as=`-typed sequence-constructor body builds a *sequence*, not a temporary tree (XSLT 3.0 §9.3) — no document node wraps it, so attribute and namespace nodes are legal members of the result. The engine left the document-construction depth at whatever the enclosing scope had, so `<xsl:attribute>` inside `<xsl:variable as="attribute()*">` looked like an attempt to attach an attribute to a document node and failed with `XTDE0420: Cannot add an attribute node to a document node`. The typed variable, param, with-param, and param-default-body seams now neutralize that depth for the body and restore it afterwards, matching what the user-function seam already did. `as="document-node()"` is deliberately excluded — that body really is wrapped in a document node. Reported by Martin Honnen against DocBook xslTNG 2.8.0 and 2.8.3 (`modules/attributes.xsl:421`), where the `<xsl:variable name="attr" as="attribute()*"><xsl:apply-templates select="@*"/></xsl:variable>` idiom appears roughly twenty times; the whole document transform failed on the sample article. Regression since the DocBook support landed in the 1.4.x–1.5.x line.
- **An `xsl:namespace` that re-declares a binding the element already has is now a no-op instead of emitting a duplicate declaration.** Adding a namespace node for a (prefix, URI) the element under construction already carries is not an error — `XTDE0430` covers only the case where the URIs *differ* — but the engine emitted both, producing two identical `xmlns:p` attributes on one start tag and output that is not well-formed XML. A conflicting URI still raises `XTDE0430`, and a redundant re-declaration of a binding an ancestor already provides is now omitted (same infoset, one fewer declaration). Found while generating DocBook xslTNG's `param.xsl` with our own engine: `tools/generate-parameters.xsl` uses `xsl:namespace-alias` to put the result root in the XSL namespace and then re-declares that same binding with `<xsl:namespace name="xsl">`, so the generated stylesheet could not be reparsed.
### Testing
- Both fixes carry regression tests (`MartinDocBookTypedAttributeVariableTests`, `NamespaceDuplicateDeclarationTests`) covering the reported shapes, the guard cases that must keep failing, and the `as="document-node()"` exclusion. Neither bug was reachable by the existing suites: the unit suite was green at 1196 and the W3C conformance suite asserts only that some tests passed, so it cannot fail on a regression. A repro harness that runs the engine against the real DocBook xslTNG stylesheets now ships in `.claude/skills/engine-repro/`; it builds a runnable xslTNG tree from a source checkout using the engine itself, with no Java, Gradle, or network dependency.