@tradik/xslt-processor 1.0.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +110 -520
  3. package/bin/lib/decode.js +15 -0
  4. package/bin/lib/dom.js +177 -0
  5. package/bin/lib/loaders.js +127 -0
  6. package/bin/lib/options.js +131 -0
  7. package/bin/lib/output.js +114 -0
  8. package/bin/lib/paths.js +186 -0
  9. package/bin/lib/transform.js +206 -0
  10. package/bin/xslt.js +73 -168
  11. package/dist/xslt-processor.browser.js +9564 -1585
  12. package/dist/xslt-processor.browser.js.map +4 -4
  13. package/dist/xslt-processor.browser.min.js +13 -2
  14. package/dist/xslt-processor.browser.min.js.map +4 -4
  15. package/dist/xslt-processor.cjs +9572 -1586
  16. package/dist/xslt-processor.cjs.map +4 -4
  17. package/dist/xslt-processor.d.cts +658 -0
  18. package/dist/xslt-processor.d.ts +459 -12
  19. package/dist/xslt-processor.js +9546 -1582
  20. package/dist/xslt-processor.js.map +4 -4
  21. package/package.json +71 -20
  22. package/src/XSLTProcessor.js +494 -48
  23. package/src/async/abort.js +63 -0
  24. package/src/async/documentUris.js +128 -0
  25. package/src/async/loaders.js +134 -0
  26. package/src/async/preload.js +159 -0
  27. package/src/async/processor.js +206 -0
  28. package/src/async/stream.js +125 -0
  29. package/src/bridge/engine.js +221 -0
  30. package/src/bridge/loader.js +78 -0
  31. package/src/bridge/results.js +75 -0
  32. package/src/bridge/version.js +63 -0
  33. package/src/index.js +26 -8
  34. package/src/io/decode.js +140 -0
  35. package/src/io/readSource.js +167 -0
  36. package/src/xpath/axes.js +562 -0
  37. package/src/xpath/documentOrder.js +270 -0
  38. package/src/xpath/evaluator.js +518 -357
  39. package/src/xpath/index.js +8 -2
  40. package/src/xpath/namespaceNodes.js +172 -0
  41. package/src/xpath/nodeSetFunctions.js +169 -0
  42. package/src/xpath/parser.js +30 -5
  43. package/src/xpath/strings.js +183 -0
  44. package/src/xpath/tokenizer.js +37 -23
  45. package/src/xslt/attributeSets.js +95 -0
  46. package/src/xslt/avt.js +103 -0
  47. package/src/xslt/computedNames.js +91 -0
  48. package/src/xslt/copying.js +212 -0
  49. package/src/xslt/declarationNames.js +80 -0
  50. package/src/xslt/domParsing.js +95 -0
  51. package/src/xslt/elements.js +57 -0
  52. package/src/xslt/engine/bindings.js +195 -0
  53. package/src/xslt/engine/context.js +105 -0
  54. package/src/xslt/engine/controlFlow.js +145 -0
  55. package/src/xslt/engine/copyInstructions.js +133 -0
  56. package/src/xslt/engine/declarations.js +233 -0
  57. package/src/xslt/engine/functionSupport.js +103 -0
  58. package/src/xslt/engine/methods.js +33 -0
  59. package/src/xslt/engine/nodeConstruction.js +187 -0
  60. package/src/xslt/engine/numbering.js +104 -0
  61. package/src/xslt/engine/outputDeclaration.js +77 -0
  62. package/src/xslt/engine/sequenceConstructor.js +228 -0
  63. package/src/xslt/engine/stylesheetLoading.js +208 -0
  64. package/src/xslt/engine/templateInvocation.js +253 -0
  65. package/src/xslt/engine/templateRules.js +243 -0
  66. package/src/xslt/engine/textInstructions.js +171 -0
  67. package/src/xslt/engine/topLevel.js +130 -0
  68. package/src/xslt/engine/transformation.js +263 -0
  69. package/src/xslt/engine/workStack.js +245 -0
  70. package/src/xslt/engine.js +184 -1736
  71. package/src/xslt/exslt/arguments.js +99 -0
  72. package/src/xslt/exslt/calendar.js +120 -0
  73. package/src/xslt/exslt/common.js +44 -0
  74. package/src/xslt/exslt/dateCalc.js +261 -0
  75. package/src/xslt/exslt/dateFormat.js +150 -0
  76. package/src/xslt/exslt/dateParse.js +265 -0
  77. package/src/xslt/exslt/dates.js +259 -0
  78. package/src/xslt/exslt/duration.js +207 -0
  79. package/src/xslt/exslt/dynamic.js +59 -0
  80. package/src/xslt/exslt/index.js +59 -0
  81. package/src/xslt/exslt/math.js +177 -0
  82. package/src/xslt/exslt/sets.js +96 -0
  83. package/src/xslt/exslt/stringOps.js +163 -0
  84. package/src/xslt/exslt/strings.js +147 -0
  85. package/src/xslt/exslt/uri.js +92 -0
  86. package/src/xslt/formatNumber.js +233 -0
  87. package/src/xslt/forwardsCompatible.js +75 -0
  88. package/src/xslt/functions.js +270 -0
  89. package/src/xslt/index.js +38 -1
  90. package/src/xslt/keys.js +164 -0
  91. package/src/xslt/literalResult.js +223 -0
  92. package/src/xslt/matchScope.js +116 -0
  93. package/src/xslt/number.js +271 -0
  94. package/src/xslt/numberFormat.js +253 -0
  95. package/src/xslt/outputNames.js +58 -0
  96. package/src/xslt/patternCompiler.js +175 -0
  97. package/src/xslt/patterns.js +324 -0
  98. package/src/xslt/qname.js +90 -0
  99. package/src/xslt/resultDocument.js +98 -0
  100. package/src/xslt/resultNamespaces.js +219 -0
  101. package/src/xslt/resultTree.js +211 -0
  102. package/src/xslt/serializer/baseWriter.js +390 -0
  103. package/src/xslt/serializer/chunks.js +120 -0
  104. package/src/xslt/serializer/constants.js +92 -0
  105. package/src/xslt/serializer/encoding.js +327 -0
  106. package/src/xslt/serializer/escape.js +135 -0
  107. package/src/xslt/serializer/frames.js +168 -0
  108. package/src/xslt/serializer/htmlDoctype.js +102 -0
  109. package/src/xslt/serializer/htmlEntities.js +77 -0
  110. package/src/xslt/serializer/htmlSerializer.js +239 -0
  111. package/src/xslt/serializer/indent.js +51 -0
  112. package/src/xslt/serializer/namespaces.js +68 -0
  113. package/src/xslt/serializer/rawText.js +41 -0
  114. package/src/xslt/serializer/settings.js +179 -0
  115. package/src/xslt/serializer/textSerializer.js +77 -0
  116. package/src/xslt/serializer/xhtmlDocument.js +103 -0
  117. package/src/xslt/serializer/xmlSerializer.js +227 -0
  118. package/src/xslt/serializer.js +90 -0
  119. package/src/xslt/sort.js +151 -0
  120. package/src/xslt/spaceNameTests.js +115 -0
  121. package/src/xslt/stylesheetChecks.js +206 -0
  122. package/src/xslt/stylesheetNamespaces.js +266 -0
  123. package/src/xslt/templatePriority.js +45 -0
  124. package/src/xslt/uri.js +68 -0
  125. package/src/xslt/variables.js +152 -0
  126. package/src/xslt/whitespace.js +200 -0
  127. package/LICENSE +0 -29
  128. package/src/XSLTProcessor.test.js +0 -930
  129. package/src/xpath/evaluator.test.js +0 -1852
  130. package/src/xpath/tokenizer.test.js +0 -224
  131. package/src/xslt/engine.test.js +0 -3130
package/README.md CHANGED
@@ -1,31 +1,62 @@
1
1
  # @tradik/xslt-processor
2
2
 
3
+ [![GitHub](https://img.shields.io/badge/GitHub-Repository-181717?logo=github)](https://github.com/spagu/XSLT-Processor)
4
+ [![GitHub stars](https://img.shields.io/github/stars/spagu/XSLT-Processor?style=social)](https://github.com/spagu/XSLT-Processor/stargazers)
5
+ [![GitHub forks](https://img.shields.io/github/forks/spagu/XSLT-Processor?style=social)](https://github.com/spagu/XSLT-Processor/network/members)
6
+
3
7
  [![CI](https://github.com/spagu/XSLT-Processor/actions/workflows/test.yml/badge.svg)](https://github.com/spagu/XSLT-Processor/actions/workflows/test.yml)
8
+ [![Browser tests](https://github.com/spagu/XSLT-Processor/actions/workflows/browser.yml/badge.svg)](https://github.com/spagu/XSLT-Processor/actions/workflows/browser.yml)
4
9
  [![Release](https://github.com/spagu/XSLT-Processor/actions/workflows/release.yml/badge.svg)](https://github.com/spagu/XSLT-Processor/actions/workflows/release.yml)
5
10
  [![npm version](https://img.shields.io/npm/v/@tradik/xslt-processor.svg)](https://www.npmjs.com/package/@tradik/xslt-processor)
6
11
  [![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
7
- [![Node.js Version](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/)
8
- [![Test Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/spagu/XSLT-Processor)
12
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.19.0-brightgreen.svg)](https://nodejs.org/)
13
+ [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=spagu_XSLT-Processor&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=spagu_XSLT-Processor)
14
+ [![Line Coverage](https://img.shields.io/badge/line%20coverage-100%25-brightgreen.svg)](docs/CONFORMANCE.md#test-coverage)
15
+ [![TypeScript](https://img.shields.io/badge/types-included-3178c6.svg?logo=typescript&logoColor=white)](docs/API.md#typescript)
16
+
17
+ > **Source Code:** [github.com/spagu/XSLT-Processor](https://github.com/spagu/XSLT-Processor)
9
18
 
10
19
  JavaScript implementation of XSLTProcessor for browser environments and Node.js CLI. This package provides a complete implementation of the W3C XSLTProcessor API that can be used as a drop-in replacement for the native browser implementation.
11
20
 
12
21
  ## Background
13
22
 
14
- Chrome and other browsers are deprecating native XSLTProcessor support:
15
- - **Chrome 143+**: XSLTProcessor starts showing deprecation warnings
16
- - **Chrome 164 (August 2027)**: Full removal of native XSLT support
23
+ Chrome and other browsers are removing native XSLT ([Chrome's announcement](https://developer.chrome.com/docs/web-platform/deprecating-xslt)):
24
+ - **Chrome 143 (December 2025)**: `XSLTProcessor` and `<?xml-stylesheet type="text/xsl"?>` are deprecated, with warnings in the console
25
+ - **Chrome 158 (17 November 2026)**: XSLT stops working in stable Chrome, except for sites in the origin trial and browsers under the enterprise policy
26
+ - **Chrome 176 (17 August 2027)**: the origin trial and the enterprise policy end; XSLT is off everywhere
27
+ - Firefox and WebKit support the removal but have not announced dates
17
28
 
18
29
  This library ensures your XSLT-based applications continue to work regardless of browser support.
19
30
 
20
31
  ## Features
21
32
 
22
33
  - **1:1 Native API Compatibility**: Drop-in replacement for native `XSLTProcessor`
23
- - **Full XSLT 1.0 Support**: Implements the complete W3C XSLT 1.0 specification
34
+ - **XSLT 1.0**: Every element and function of the W3C XSLT 1.0 Recommendation, with the few gaps listed under [Known Deviations](docs/CONFORMANCE.md#known-deviations)
24
35
  - **XPath 1.0 Engine**: Built-in XPath evaluator with all core functions
25
- - **Zero Dependencies**: Standalone implementation with no external dependencies
36
+ - **`xsl:output` Serialization**: `transformToString()` honors method, indent, doctype, CDATA sections and `disable-output-escaping`
37
+ - **Zero Dependencies**: The library has no runtime dependencies; only the `xslt` command line tool needs `jsdom` (an optional peer dependency)
26
38
  - **Multiple Formats**: ESM, CommonJS, and browser IIFE bundles
27
39
  - **TypeScript Support**: Includes TypeScript declarations
28
- - **WCAG 2.2 Compliant**: Designed with accessibility in mind
40
+
41
+ ## Documentation
42
+
43
+ The documentation is also published as a website with an interactive playground: <https://xslt-processor.tradik.com/> ([playground](https://xslt-processor.tradik.com/playground/): XSLT 1.0 transformations, and with the in-development `@tradik/xslt3` XSLT 3.0 stylesheets at [?mode=xslt3](https://xslt-processor.tradik.com/playground/?mode=xslt3) and XPath 3.1 expressions at [?mode=xpath](https://xslt-processor.tradik.com/playground/?mode=xpath); [blog](https://xslt-processor.tradik.com/blog/) with an [RSS feed](https://xslt-processor.tradik.com/blog/rss.xml)).
44
+
45
+ | Guide | Contents |
46
+ |-------|----------|
47
+ | [API Reference](docs/API.md) | `XSLTProcessor` methods, parameters, `xsl:output` serialization, module exports, `XsltEngine` options, TypeScript |
48
+ | [Loaders](docs/LOADERS.md) | `xsl:import`, `xsl:include` and the `document()` function |
49
+ | [Complete Example](docs/EXAMPLES.md) | A product list transformed into an HTML table (browser and CLI) |
50
+ | [Command Line Tool](docs/CLI.md) | `xslt` options, base directory, includes, input encodings |
51
+ | [Conformance](docs/CONFORMANCE.md) | W3C compliance tables, supported elements and functions, known deviations, test coverage |
52
+ | [Security Limits](docs/SECURITY-LIMITS.md) | XPath and XSLT limits, prototype pollution protection, input validation |
53
+ | [Browser Compatibility](docs/BROWSER-SUPPORT.md) | Minimum browser versions, native XSLT removal timeline, feature detection |
54
+ | [XSLT 2.0 and 3.0](docs/XSLT3.md) | In development: one engine for XSLT 3.0 and 2.0 in a separate package, `@tradik/xslt3`; design, scope and milestones |
55
+ | [Benchmarks](docs/BENCHMARKS.md) | 1.1.3 vs 1.2.0: speed-up, time and peak memory per scenario, with charts, tables and `npm run bench` to reproduce; XPath 1.0 of this package vs XPath 3.1 of @tradik/xslt3 (`npm run bench -- --suite xpath`); the XSLT 1.0 engine vs @tradik/xslt3 on the same stylesheets, idiomatic 2.0/3.0 rewrites and 3.0-only scenarios (`npm run bench -- --suite xslt`) |
56
+ | [Development](docs/DEVELOPMENT.md) | Setup, tests, Docker, Makefile, publishing to npm |
57
+ | [Style Guide](docs/STYLE-GUIDE.md) | Project colors with WCAG 2.2 contrast ratios |
58
+
59
+ All guides are listed in the [documentation index](docs/README.md).
29
60
 
30
61
  ## Installation
31
62
 
@@ -33,7 +64,10 @@ This library ensures your XSLT-based applications continue to work regardless of
33
64
  npm install @tradik/xslt-processor
34
65
  ```
35
66
 
36
- ## Usage
67
+ The library itself has no dependencies. The `xslt` command line tool also
68
+ needs `jsdom` (an optional peer dependency, `>=25`), see [CLI Usage](#cli-usage).
69
+
70
+ ## Quick Start
37
71
 
38
72
  ### Browser via CDN (Recommended)
39
73
 
@@ -47,7 +81,7 @@ Use a CDN for the easiest browser integration - no build step required:
47
81
  <script src="https://unpkg.com/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js"></script>
48
82
 
49
83
  <script>
50
- // XSLTProcessor is now available globally
84
+ // XSLTProcessor is the native one, or this polyfill when native XSLT is unavailable
51
85
  const processor = new XSLTProcessor();
52
86
 
53
87
  // Load and transform XML
@@ -61,13 +95,20 @@ Use a CDN for the easiest browser integration - no build step required:
61
95
  </script>
62
96
  ```
63
97
 
98
+ The bundle defines the global `XsltProcessorLib` (all [module exports](docs/API.md#module-exports))
99
+ and calls `installGlobal()`: `window.XSLTProcessor` is replaced only when the
100
+ browser has no working native implementation. To always use this
101
+ implementation, call `XsltProcessorLib.installGlobal(true)` or use
102
+ `new XsltProcessorLib.XSLTProcessor()`.
103
+
64
104
  **CDN URLs:**
105
+
65
106
  | CDN | URL |
66
107
  |-----|-----|
67
108
  | jsDelivr | `https://cdn.jsdelivr.net/npm/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js` |
68
109
  | unpkg | `https://unpkg.com/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js` |
69
110
 
70
- > **Tip:** Use `@1` for latest 1.x version, or `@1.0.0` for exact version pinning.
111
+ > **Tip:** Use `@1` for the latest 1.x version, or an exact version such as `@1.1.3` for pinning.
71
112
 
72
113
  ### Browser (Local Install)
73
114
 
@@ -117,546 +158,95 @@ const processor = new XSLTProcessor();
117
158
  // ...
118
159
  ```
119
160
 
120
- ### CLI Usage
121
-
122
- The package includes a command-line tool for transforming XML documents:
123
-
124
- ```bash
125
- # Global installation
126
- npm install -g @tradik/xslt-processor
127
-
128
- # Transform XML with XSLT
129
- xslt data.xml template.xsl
130
-
131
- # Save output to file
132
- xslt data.xml template.xsl -o result.html
133
-
134
- # With parameters
135
- xslt data.xml template.xsl -p title="My Page" -p count=10
136
-
137
- # Format output with indentation
138
- xslt data.xml template.xsl -f -o output.html
139
- ```
140
-
141
- #### CLI Options
142
-
143
- | Option | Description |
144
- |--------|-------------|
145
- | `-o, --output <file>` | Write output to file instead of stdout |
146
- | `-p, --param <n>=<v>` | Set XSLT parameter (can be used multiple times) |
147
- | `-f, --format` | Format output with indentation |
148
- | `-h, --help` | Show help message |
149
- | `-v, --version` | Show version number |
161
+ ### Node.js
150
162
 
151
- ## API Reference
163
+ Node.js has no DOM, so bring one such as `jsdom`. The
164
+ [filesystem loader example](docs/LOADERS.md#nodejs-example-filesystem-loader)
165
+ is a complete Node.js script, and the [API Reference](docs/API.md) covers every
166
+ method.
152
167
 
153
- ### XSLTProcessor
168
+ ### XSLT 2.0 and 3.0 (opt-in)
154
169
 
155
- #### Constructor
170
+ By default every stylesheet runs with the XSLT 1.0 engine, and a
171
+ `version="2.0"` stylesheet runs in forwards-compatible mode, as in Chrome.
172
+ With `xsltVersion: "auto"`, a stylesheet that declares version 2.0 or 3.0 is
173
+ run by [`@tradik/xslt3`](docs/XSLT3.md), an optional peer dependency loaded
174
+ with `import()` only when such a stylesheet is imported, so the XSLT 1.0
175
+ bundles do not grow by the size of the new engine:
156
176
 
157
177
  ```javascript
158
- const processor = new XSLTProcessor();
159
- ```
160
-
161
- #### Methods
162
-
163
- | Method | Description |
164
- |--------|-------------|
165
- | `importStylesheet(node)` | Imports an XSLT stylesheet from a Document or Element node |
166
- | `transformToFragment(source, output)` | Transforms XML and returns a DocumentFragment |
167
- | `transformToDocument(source)` | Transforms XML and returns an XMLDocument |
168
- | `setParameter(namespaceURI, localName, value)` | Sets an XSLT parameter |
169
- | `getParameter(namespaceURI, localName)` | Gets an XSLT parameter value |
170
- | `removeParameter(namespaceURI, localName)` | Removes an XSLT parameter |
171
- | `clearParameters()` | Removes all parameters |
172
- | `reset()` | Resets the processor, removing stylesheet and parameters |
173
-
174
- ### Parameters Example
175
-
176
- ```javascript
177
- const processor = new XSLTProcessor();
178
- processor.importStylesheet(xsltDoc);
179
-
180
- // Set parameters
181
- processor.setParameter(null, 'sortOrder', 'ascending');
182
- processor.setParameter(null, 'itemsPerPage', 10);
183
-
184
- // Get parameter
185
- const sortOrder = processor.getParameter(null, 'sortOrder');
186
-
187
- // Clear parameters
188
- processor.clearParameters();
189
- ```
190
-
191
- ### Using xsl:import and xsl:include
192
-
193
- To use `xsl:import` and `xsl:include` elements in your stylesheets, you need to configure a stylesheet loader that tells the processor how to fetch external stylesheets:
194
-
195
- ```javascript
196
- import { XSLTProcessor } from '@tradik/xslt-processor';
197
-
198
- const processor = new XSLTProcessor();
199
-
200
- // Configure stylesheet loader
201
- processor.engine.setStylesheetLoader((href, baseUri) => {
202
- // href: the href attribute from xsl:import/xsl:include
203
- // baseUri: the URI of the importing stylesheet
204
-
205
- // Option 1: Return a parsed Document
206
- const response = await fetch(href);
207
- const text = await response.text();
208
- const parser = new DOMParser();
209
- return parser.parseFromString(text, 'application/xml');
210
-
211
- // Option 2: Return XML string (will be parsed automatically)
212
- return await fetch(href).then(r => r.text());
213
- });
214
-
215
- // Now xsl:import and xsl:include will work
216
- processor.importStylesheet(mainStylesheet, '/styles/main.xsl');
217
- ```
218
-
219
- #### Import vs Include Behavior
220
-
221
- - **xsl:include**: Merges templates at the same precedence level. If multiple templates match, priority attribute decides.
222
- - **xsl:import**: Imported templates have lower precedence than importing stylesheet. The importing stylesheet's templates always win over imported ones with the same match pattern.
223
-
224
- ```xml
225
- <!-- main.xsl -->
226
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
227
- <xsl:import href="base.xsl"/> <!-- imported templates have lower precedence -->
228
- <xsl:include href="utils.xsl"/> <!-- included templates have same precedence -->
229
-
230
- <xsl:template match="item">
231
- <!-- This template overrides the one from base.xsl -->
232
- </xsl:template>
233
- </xsl:stylesheet>
234
- ```
178
+ // npm install @tradik/xslt3
179
+ const processor = new XSLTProcessor({ xsltVersion: "auto" });
180
+ const html = await processor.transformAsync(xmlText, { stylesheet: xsl20Text });
235
181
 
236
- ### Utility Functions
237
-
238
- ```javascript
239
- import { isNativeXSLTSupported, installGlobal } from '@tradik/xslt-processor';
240
-
241
- // Check if native XSLT is functional
242
- if (!isNativeXSLTSupported()) {
243
- console.log('Using JS implementation');
244
- }
245
-
246
- // Install as global XSLTProcessor
247
- installGlobal(); // Only if native not available
248
- installGlobal(true); // Force install
249
- ```
250
-
251
- ## Complete Example
252
-
253
- Here's a full example transforming a list of products into an HTML table:
254
-
255
- **products.xml:**
256
- ```xml
257
- <?xml version="1.0"?>
258
- <products>
259
- <product id="1">
260
- <name>Widget</name>
261
- <price>29.99</price>
262
- <stock>150</stock>
263
- </product>
264
- <product id="2">
265
- <name>Gadget</name>
266
- <price>49.99</price>
267
- <stock>75</stock>
268
- </product>
269
- </products>
270
- ```
271
-
272
- **products.xsl:**
273
- ```xml
274
- <?xml version="1.0"?>
275
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
276
- <xsl:param name="title" select="'Product Catalog'"/>
277
-
278
- <xsl:template match="/">
279
- <html>
280
- <head><title><xsl:value-of select="$title"/></title></head>
281
- <body>
282
- <h1><xsl:value-of select="$title"/></h1>
283
- <table>
284
- <tr><th>ID</th><th>Name</th><th>Price</th><th>Stock</th></tr>
285
- <xsl:apply-templates select="products/product">
286
- <xsl:sort select="name"/>
287
- </xsl:apply-templates>
288
- </table>
289
- </body>
290
- </html>
291
- </xsl:template>
292
-
293
- <xsl:template match="product">
294
- <tr>
295
- <td><xsl:value-of select="@id"/></td>
296
- <td><xsl:value-of select="name"/></td>
297
- <td>$<xsl:value-of select="price"/></td>
298
- <td>
299
- <xsl:choose>
300
- <xsl:when test="stock > 100">In Stock</xsl:when>
301
- <xsl:when test="stock > 0">Low Stock</xsl:when>
302
- <xsl:otherwise>Out of Stock</xsl:otherwise>
303
- </xsl:choose>
304
- </td>
305
- </tr>
306
- </xsl:template>
307
- </xsl:stylesheet>
308
- ```
309
-
310
- **JavaScript:**
311
- ```javascript
312
- import { XSLTProcessor } from '@tradik/xslt-processor';
313
-
314
- const processor = new XSLTProcessor();
315
- processor.importStylesheet(xsltDoc);
316
- processor.setParameter(null, 'title', 'My Product List');
317
-
318
- const result = processor.transformToFragment(xmlDoc, document);
319
- document.body.appendChild(result);
320
- ```
321
-
322
- **CLI:**
323
- ```bash
324
- xslt products.xml products.xsl -p title="My Product List" -f -o catalog.html
182
+ // The synchronous W3C API needs the engine loaded first
183
+ await XSLTProcessor.preload();
184
+ processor.importStylesheet(xsl20Doc);
185
+ const fragment = processor.transformToFragment(xmlDoc, document);
325
186
  ```
326
187
 
327
- ## Security Features
328
-
329
- The XPath evaluator includes comprehensive security hardening to prevent common attack vectors.
330
-
331
- ### DoS Prevention Limits
332
-
333
- | Limit | Default | Description |
334
- |-------|---------|-------------|
335
- | `MAX_RECURSION_DEPTH` | 100 | Prevents stack overflow from deeply nested expressions |
336
- | `MAX_RESULT_SIZE` | 10,000 | Prevents memory exhaustion from large result sets |
337
- | `MAX_STRING_LENGTH` | 1,000,000 | Limits string processing to prevent memory issues |
338
-
339
- ### Prototype Pollution Protection
340
-
341
- The following variable names are blocked:
342
- - `__proto__`, `constructor`, `prototype`
343
- - `__defineGetter__`, `__defineSetter__`
344
- - `__lookupGetter__`, `__lookupSetter__`
345
-
346
- ### Input Validation
347
-
348
- - **AST Validation**: All AST nodes are validated before evaluation
349
- - **Type Safety**: Strict type checking on all inputs
350
- - **Safe Variable Lookup**: Uses `hasOwnProperty` to prevent prototype chain attacks
351
-
352
- ### Custom Security Limits
353
-
354
- ```javascript
355
- import { XPathEvaluator, XPathContext, parse } from '@tradik/xslt-processor';
356
-
357
- const evaluator = new XPathEvaluator({
358
- maxRecursionDepth: 50, // Lower for untrusted input
359
- maxResultSize: 1000, // Limit result set size
360
- maxStringLength: 10000 // Limit string operations
361
- });
362
-
363
- const ast = parse('//item');
364
- const context = new XPathContext(xmlDoc);
365
- const result = evaluator.evaluate(ast, context);
366
- ```
188
+ The CLI flag is `--xslt-version auto`. Details: [Opt-in XSLT 2.0/3.0](docs/API.md#opt-in-xslt-2030).
367
189
 
368
- ## XSLT Elements Supported
369
-
370
- | Element | Status |
371
- |---------|--------|
372
- | `xsl:apply-templates` | Supported |
373
- | `xsl:attribute` | Supported |
374
- | `xsl:call-template` | Supported |
375
- | `xsl:choose` / `when` / `otherwise` | Supported |
376
- | `xsl:comment` | Supported |
377
- | `xsl:copy` | Supported |
378
- | `xsl:copy-of` | Supported |
379
- | `xsl:element` | Supported |
380
- | `xsl:for-each` | Supported |
381
- | `xsl:if` | Supported |
382
- | `xsl:message` | Supported |
383
- | `xsl:number` | Supported |
384
- | `xsl:output` | Supported |
385
- | `xsl:param` | Supported |
386
- | `xsl:processing-instruction` | Supported |
387
- | `xsl:sort` | Supported |
388
- | `xsl:template` | Supported |
389
- | `xsl:text` | Supported |
390
- | `xsl:value-of` | Supported |
391
- | `xsl:variable` | Supported |
392
- | `xsl:with-param` | Supported |
393
- | `xsl:import` | Supported |
394
- | `xsl:include` | Supported |
395
-
396
- ## XPath Functions Supported
397
-
398
- ### Node Set Functions
399
- - `count()`, `id()`, `last()`, `local-name()`, `name()`, `namespace-uri()`, `position()`
400
-
401
- ### String Functions
402
- - `concat()`, `contains()`, `normalize-space()`, `starts-with()`, `string()`, `string-length()`, `substring()`, `substring-after()`, `substring-before()`, `translate()`
403
-
404
- ### Boolean Functions
405
- - `boolean()`, `false()`, `lang()`, `not()`, `true()`
406
-
407
- ### Number Functions
408
- - `ceiling()`, `floor()`, `number()`, `round()`, `sum()`
409
-
410
- ## Development
411
-
412
- ### Prerequisites
413
-
414
- - Node.js 25+ (for native test runner)
415
- - Docker (optional, for containerized testing)
416
-
417
- ### Setup
190
+ ## CLI Usage
418
191
 
419
- ```bash
420
- cd services/xslt-processor
421
- npm install
422
- ```
192
+ The package includes a command-line tool for transforming XML documents.
423
193
 
424
- ### Commands
194
+ Without Node.js, use the standalone executable attached to every GitHub
195
+ release (Linux x64/arm64, macOS x64/arm64, Windows x64), installed with a
196
+ checksum check:
425
197
 
426
198
  ```bash
427
- # Run tests
428
- npm test
429
-
430
- # Run tests with watch mode
431
- npm run test:watch
432
-
433
- # Build bundles
434
- npm run build
435
-
436
- # Lint code
437
- npm run lint
438
-
439
- # Format code
440
- npm run format
199
+ curl -fsSL https://raw.githubusercontent.com/spagu/XSLT-Processor/main/scripts/install.sh | bash
441
200
  ```
442
201
 
443
- ### Docker
202
+ See [Standalone executables](docs/CLI.md#standalone-executables) for manual
203
+ installation. With Node.js, the command line tool needs a DOM implementation, so install `jsdom` next to
204
+ the package. It is an optional peer dependency: library users do not need it.
205
+ Without it, `xslt` exits with an explanation instead of a stack trace.
444
206
 
445
207
  ```bash
446
- # Run tests in container
447
- docker-compose run test
448
-
449
- # Development with hot reload
450
- docker-compose run dev
451
-
452
- # Build bundles
453
- docker-compose run build
454
- ```
455
-
456
- ### Publishing to npm
208
+ # Global installation
209
+ npm install -g @tradik/xslt-processor jsdom
457
210
 
458
- The package is automatically published to npm when a GitHub release is created or a version tag is pushed.
211
+ # Transform XML with XSLT
212
+ xslt data.xml template.xsl
459
213
 
460
- **Prerequisites:**
461
- 1. Set up `NPM_TOKEN` secret in GitHub repository settings
462
- 2. Ensure version in `package.json` matches the release tag
214
+ # Save output to file
215
+ xslt data.xml template.xsl -o result.html
463
216
 
464
- **Release Process:**
217
+ # With parameters
218
+ xslt data.xml template.xsl -p title="My Page" -p count=10
465
219
 
466
- ```bash
467
- # 1. Update version in package.json
468
- npm version patch # or minor, major
220
+ # Format output with indentation
221
+ xslt data.xml template.xsl -f -o output.html
469
222
 
470
- # 2. Push the tag
471
- git push origin --tags
223
+ # Override the output method and drop the XML declaration
224
+ xslt data.xml template.xsl --method text
225
+ xslt data.xml template.xsl --no-declaration
472
226
 
473
- # 3. Create a GitHub release (or push triggers automatically)
227
+ # Run an XSLT 2.0/3.0 stylesheet with @tradik/xslt3 (npm install -g @tradik/xslt3)
228
+ xslt data.xml grouping.xsl --xslt-version auto
474
229
  ```
475
230
 
476
- **Automated Workflow:**
477
- 1. Runs all tests and linting checks
478
- 2. Performs security audit with `npm audit`
479
- 3. Builds distribution bundles
480
- 4. Publishes to npm with provenance (supply chain security)
481
- 5. Uploads build artifacts to GitHub
482
-
483
- ## Browser Compatibility
484
-
485
- This library provides a JavaScript polyfill for XSLTProcessor that works across all modern browsers.
486
-
487
- ### Polyfill Support
231
+ See [Command Line Tool](docs/CLI.md) for all options, the base directory,
232
+ `xsl:include`/`document()` resolution and input encodings.
488
233
 
489
- | Browser | Minimum Version | ES Modules | Status |
490
- |---------|-----------------|------------|--------|
491
- | Chrome | 90+ | Yes | Fully Supported |
492
- | Firefox | 88+ | Yes | Fully Supported |
493
- | Safari | 14+ | Yes | Fully Supported |
494
- | Edge | 90+ | Yes | Fully Supported |
495
- | Opera | 76+ | Yes | Fully Supported |
496
- | Samsung Internet | 15+ | Yes | Fully Supported |
497
- | Node.js | 25+ | Yes | Fully Supported |
234
+ ## Known Deviations
498
235
 
499
- ### Native XSLT Deprecation Timeline
236
+ The main differences from XSLT 1.0 / XPath 1.0 and from libxslt:
500
237
 
501
- | Browser | Deprecation Warning | Full Removal |
502
- |---------|---------------------|--------------|
503
- | Chrome | v143 (2026) | v164 (August 2027) |
504
- | Edge | v143 (2026) | v164 (August 2027) |
505
- | Other Chromium | v143 (2026) | v164 (August 2027) |
238
+ - `xsl:number` ignores `lang` and `letter-value`;
239
+ - `unparsed-entity-uri()` always returns `''`;
240
+ - numbers convert to strings in the XPath 1.0 form (`10000000000`), where libxslt writes `1e+10`.
506
241
 
507
- ### Feature Detection
242
+ Details and workarounds: [Known Deviations](docs/CONFORMANCE.md#known-deviations).
508
243
 
509
- ```javascript
510
- import { isNativeXSLTSupported, installGlobal } from '@tradik/xslt-processor';
511
-
512
- // Check native support and auto-install polyfill
513
- if (!isNativeXSLTSupported()) {
514
- installGlobal();
515
- console.log('Using JavaScript XSLT polyfill');
516
- }
517
- ```
244
+ ## Contributing and Security
518
245
 
519
- ## W3C Standards Compliance
520
-
521
- This implementation follows these W3C specifications with comprehensive test coverage to ensure compliance.
522
-
523
- ### Specifications Implemented
524
-
525
- | Specification | Version | Status |
526
- |---------------|---------|--------|
527
- | [XPath 1.0](http://www.w3.org/TR/1999/REC-xpath-19991116) | W3C Recommendation, 16 November 1999 | Full Compliance |
528
- | [XSLT 1.0](http://www.w3.org/TR/1999/REC-xslt-19991116) | W3C Recommendation, 16 November 1999 | Full Compliance |
529
- | [DOM Level 3 Core](http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/) | W3C Recommendation, 7 April 2004 | Full Compliance |
530
-
531
- ### XSLT 1.0 Specification Compliance
532
-
533
- | Section | Feature | Status | Notes |
534
- |---------|---------|--------|-------|
535
- | 2 | Stylesheet Structure | Supported | `xsl:stylesheet`, `xsl:transform` elements |
536
- | 3 | Data Model | Supported | Seven node types per XPath data model |
537
- | 5 | Template Rules | Supported | Pattern matching, priority calculation |
538
- | 5.1 | Processing Model | Supported | Built-in templates for all node types |
539
- | 5.2 | Patterns | Supported | All pattern syntax including predicates |
540
- | 5.3 | Defining Template Rules | Supported | `match`, `name`, `priority`, `mode` attributes |
541
- | 5.4 | Applying Template Rules | Supported | `xsl:apply-templates` with `select`, `mode` |
542
- | 5.5 | Conflict Resolution | Supported | Import precedence and priority ordering |
543
- | 6 | Named Templates | Supported | `xsl:call-template`, `xsl:with-param` |
544
- | 7 | Creating Result Tree | Supported | Literal result elements, attribute value templates |
545
- | 7.1.2 | Creating Elements | Supported | `xsl:element` with dynamic names/namespaces |
546
- | 7.1.3 | Creating Attributes | Supported | `xsl:attribute` with dynamic names/namespaces |
547
- | 7.2 | Creating Text | Supported | `xsl:value-of`, `xsl:text` |
548
- | 7.3 | Creating PIs | Supported | `xsl:processing-instruction` |
549
- | 7.4 | Creating Comments | Supported | `xsl:comment` |
550
- | 7.5 | Copying | Supported | `xsl:copy`, `xsl:copy-of` |
551
- | 7.6 | Attribute Sets | Supported | `xsl:attribute-set`, `use-attribute-sets` |
552
- | 7.6.2 | Namespace Aliases | Supported | `xsl:namespace-alias` |
553
- | 8 | Repetition | Supported | `xsl:for-each` |
554
- | 9 | Conditional Processing | Supported | `xsl:if`, `xsl:choose`, `xsl:when`, `xsl:otherwise` |
555
- | 10 | Sorting | Supported | `xsl:sort` with multiple keys, data-types, order |
556
- | 11 | Variables/Parameters | Supported | `xsl:variable`, `xsl:param`, scoping rules |
557
- | 11.1 | Result Tree Fragments | Supported | RTF handling as per spec |
558
- | 12 | Additional Functions | Supported | `document()`, `key()`, `format-number()`, `current()`, `generate-id()`, `system-property()` |
559
- | 12.3 | Number Formatting | Supported | `xsl:number` with all formatting options |
560
- | 13 | Messages | Supported | `xsl:message` with `terminate` attribute |
561
- | 14 | Extensions | Partial | `xsl:fallback` supported |
562
- | 15 | Fallback | Supported | `xsl:fallback` element |
563
- | 16 | Output | Supported | `xsl:output` with method, encoding, indent |
564
-
565
- ### XPath 1.0 Specification Compliance
566
-
567
- | Section | Feature | Status | Notes |
568
- |---------|---------|--------|-------|
569
- | 2.1 | Location Steps | Supported | axis::node-test[predicate] |
570
- | 2.2 | Axes | Supported | All 13 axes implemented |
571
- | 2.3 | Node Tests | Supported | Name tests, `node()`, `text()`, `comment()`, `processing-instruction()` |
572
- | 2.4 | Predicates | Supported | Position and boolean predicates |
573
- | 2.5 | Abbreviated Syntax | Supported | `.`, `..`, `@`, `//` |
574
- | 3.1 | Basics | Supported | Expression evaluation |
575
- | 3.2 | Function Calls | Supported | All core functions |
576
- | 3.3 | Node-sets | Supported | Union operator `\|` |
577
- | 3.4 | Booleans | Supported | `and`, `or`, `not()` |
578
- | 3.5 | Numbers | Supported | IEEE 754 double-precision |
579
- | 3.6 | Strings | Supported | Unicode string handling |
580
- | 3.7 | Lexical Structure | Supported | Full tokenization |
581
- | 4.1 | Node Set Functions | Supported | `last()`, `position()`, `count()`, `id()`, `local-name()`, `namespace-uri()`, `name()` |
582
- | 4.2 | String Functions | Supported | `string()`, `concat()`, `starts-with()`, `contains()`, `substring-before()`, `substring-after()`, `substring()`, `string-length()`, `normalize-space()`, `translate()` |
583
- | 4.3 | Boolean Functions | Supported | `boolean()`, `not()`, `true()`, `false()`, `lang()` |
584
- | 4.4 | Number Functions | Supported | `number()`, `sum()`, `floor()`, `ceiling()`, `round()` |
585
-
586
- ### XPath Axes Implementation
587
-
588
- | Axis | Status | Description |
589
- |------|--------|-------------|
590
- | `child` | Supported | Children of context node |
591
- | `descendant` | Supported | Descendants of context node |
592
- | `parent` | Supported | Parent of context node |
593
- | `ancestor` | Supported | Ancestors of context node |
594
- | `following-sibling` | Supported | Following siblings |
595
- | `preceding-sibling` | Supported | Preceding siblings |
596
- | `following` | Supported | Nodes after context in document order |
597
- | `preceding` | Supported | Nodes before context in document order |
598
- | `attribute` | Supported | Attributes of context node |
599
- | `namespace` | Supported | Namespace nodes |
600
- | `self` | Supported | Context node itself |
601
- | `descendant-or-self` | Supported | Context node and descendants |
602
- | `ancestor-or-self` | Supported | Context node and ancestors |
603
-
604
- ### DOM Level 3 Core Compliance
605
-
606
- | Interface | Status | Notes |
607
- |-----------|--------|-------|
608
- | `Node` | Supported | All node type constants |
609
- | `Document` | Supported | `createElement`, `createTextNode`, `createComment`, etc. |
610
- | `Element` | Supported | `getAttribute`, `setAttribute`, namespace methods |
611
- | `Attr` | Supported | Attribute nodes with namespace support |
612
- | `Text` | Supported | Text node handling |
613
- | `Comment` | Supported | Comment nodes |
614
- | `ProcessingInstruction` | Supported | PI nodes with target and data |
615
- | `DocumentFragment` | Supported | Fragment handling in transforms |
616
- | `NamedNodeMap` | Supported | Attribute collections |
617
- | `NodeList` | Supported | Child node collections |
618
-
619
- ### Web API Compliance
620
-
621
- This implementation provides full compatibility with the [MDN XSLTProcessor API](https://developer.mozilla.org/en-US/docs/Web/API/XSLTProcessor):
622
-
623
- | Method | Status | Notes |
624
- |--------|--------|-------|
625
- | `importStylesheet(node)` | Supported | Accepts Document or Element |
626
- | `transformToFragment(source, output)` | Supported | Returns DocumentFragment |
627
- | `transformToDocument(source)` | Supported | Returns XMLDocument |
628
- | `setParameter(namespaceURI, localName, value)` | Supported | Full namespace support |
629
- | `getParameter(namespaceURI, localName)` | Supported | Returns parameter value |
630
- | `removeParameter(namespaceURI, localName)` | Supported | Removes single parameter |
631
- | `clearParameters()` | Supported | Removes all parameters |
632
- | `reset()` | Supported | Resets processor state |
633
-
634
- ### Test Coverage by Specification
635
-
636
- | Specification | Tests | Coverage |
637
- |---------------|-------|----------|
638
- | XSLT 1.0 Elements | 82+ | 100% of supported elements |
639
- | XPath 1.0 Functions | 50+ | 100% of core functions |
640
- | XPath 1.0 Axes | 26+ | All 13 axes |
641
- | DOM Level 3 | 20+ | Core interfaces |
642
- | XSLTProcessor API | 39+ | All methods |
643
- | Security | 34+ | DoS prevention, prototype pollution |
644
- | **Total** | **441** | **99.41% line coverage** |
645
-
646
- ## Style Guide
647
-
648
- ### Colors
649
-
650
- | Usage | Color | Hex |
651
- |-------|-------|-----|
652
- | Primary | Blue | `#2563eb` |
653
- | Success | Green | `#16a34a` |
654
- | Warning | Amber | `#d97706` |
655
- | Error | Red | `#dc2626` |
656
- | Text | Gray | `#1f2937` |
657
- | Background | White | `#ffffff` |
658
-
659
- All colors meet WCAG 2.2 AA contrast requirements for accessibility.
246
+ - [CONTRIBUTORS.md](CONTRIBUTORS.md) - how to contribute
247
+ - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
248
+ - [SECURITY.md](SECURITY.md) - reporting vulnerabilities and the threat model
249
+ - [CHANGELOG.md](CHANGELOG.md) - release history
660
250
 
661
251
  ## License
662
252