xslt-processor 4.8.5 → 4.9.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.
- package/README.md +70 -10
- package/index.d.mts +7 -0
- package/index.d.ts +7 -0
- package/index.js +37 -13
- package/index.js.map +1 -1
- package/index.mjs +37 -13
- package/index.mjs.map +1 -1
- package/package.json +1 -1
- package/umd/xslt-processor.global.js +5 -5
- package/umd/xslt-processor.global.js.map +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ _A JavaScript XSLT processor without native library dependencies._
|
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="https://github.com/DesignLiquido/xslt-processor/issues" target="_blank">
|
|
7
|
-
<img src="https://img.shields.io/github/issues/
|
|
7
|
+
<img src="https://img.shields.io/github/issues/DesignLiquido/xslt-processor" />
|
|
8
8
|
</a>
|
|
9
9
|
<img src="https://img.shields.io/github/stars/Designliquido/xslt-processor" />
|
|
10
10
|
<img src="https://img.shields.io/github/forks/Designliquido/xslt-processor" />
|
|
@@ -37,7 +37,7 @@ ohpm install xslt-processor
|
|
|
37
37
|
yarn add xslt-processor
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
Within your ES2015+ code, import the `Xslt` class, the `XmlParser` class and use this way:
|
|
40
|
+
Within your ES2015+ code, import the `Xslt` class, the `XmlParser` class and use it this way:
|
|
41
41
|
|
|
42
42
|
```js
|
|
43
43
|
import { Xslt, XmlParser } from 'xslt-processor'
|
|
@@ -80,11 +80,44 @@ const xslt = new Xslt(options);
|
|
|
80
80
|
- `cData` (`boolean`, default `true`): resolves CDATA elements in the output. Content under CDATA is resolved as text. This overrides `escape` for CDATA content.
|
|
81
81
|
- `escape` (`boolean`, default `true`): replaces symbols like `<`, `>`, `&` and `"` by the corresponding [HTML/XML entities](https://www.tutorialspoint.com/xml/xml_character_entities.htm). Can be overridden by `disable-output-escaping`, that also does the opposite, unescaping `>` and `<` by `<` and `>`, respectively.
|
|
82
82
|
- `selfClosingTags` (`boolean`, default `true`): Self-closes tags that don't have inner elements, if `true`. For instance, `<test></test>` becomes `<test />`.
|
|
83
|
-
- `outputMethod` (`string`, default `xml`): Specifies the default output method.
|
|
83
|
+
- `outputMethod` (`string`, default `xml`): Specifies the default output method. If `<xsl:output>` is declared in your XSLT file, this will be overridden. Valid values: `xml`, `html`, `text`, `xhtml`, `json`, `adaptive`.
|
|
84
84
|
- `parameters` (`array`, default `[]`): external parameters that you want to use.
|
|
85
85
|
- `name`: the parameter name;
|
|
86
86
|
- `namespaceUri` (optional): the namespace;
|
|
87
87
|
- `value`: the value.
|
|
88
|
+
- `fetchFunction` (`(uri: string) => Promise<string>`, optional): a custom function for loading external resources referenced by `<xsl:import>` and `<xsl:include>`. Receives the URI and must return the fetched content as a string. Defaults to the global `fetch` API. This is useful for:
|
|
89
|
+
- Denying external loading entirely;
|
|
90
|
+
- Loading from the local filesystem or other non-HTTP sources;
|
|
91
|
+
- Transforming or remapping URIs before fetching.
|
|
92
|
+
|
|
93
|
+
**`fetchFunction` examples:**
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
import { readFileSync } from 'fs';
|
|
97
|
+
|
|
98
|
+
// Deny all external loading
|
|
99
|
+
const xslt = new Xslt({
|
|
100
|
+
fetchFunction: async (uri) => {
|
|
101
|
+
throw new Error(`External loading is not allowed: ${uri}`);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Load from local filesystem
|
|
106
|
+
const xslt = new Xslt({
|
|
107
|
+
fetchFunction: async (uri) => {
|
|
108
|
+
return readFileSync(uri, 'utf-8');
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Remap URIs before fetching
|
|
113
|
+
const xslt = new Xslt({
|
|
114
|
+
fetchFunction: async (uri) => {
|
|
115
|
+
const remapped = uri.replace('https://example.com/', '/local/stylesheets/');
|
|
116
|
+
const response = await fetch(remapped);
|
|
117
|
+
return response.text();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
```
|
|
88
121
|
|
|
89
122
|
#### JSON Output Format
|
|
90
123
|
|
|
@@ -182,10 +215,10 @@ console.log(result2); // "<users><user>John</user></users>" (XML)
|
|
|
182
215
|
You can simply add a tag like this:
|
|
183
216
|
|
|
184
217
|
```html
|
|
185
|
-
<script type="application/javascript" src="https://
|
|
218
|
+
<script type="application/javascript" src="https://unpkg.com/xslt-processor@latest/umd/xslt-processor.global.js"></script>
|
|
186
219
|
```
|
|
187
220
|
|
|
188
|
-
All the exports will live under `globalThis.XsltProcessor` and `window.XsltProcessor`. [See a usage example here](https://github.com/DesignLiquido/xslt-processor/blob/main/interactive-tests/xslt.html).
|
|
221
|
+
All the exports will live under `globalThis.XsltProcessor` and `window.XsltProcessor`. [See a usage example here](https://github.com/DesignLiquido/xslt-processor/blob/main/interactive-tests/xslt.html).
|
|
189
222
|
|
|
190
223
|
## XPath Parser
|
|
191
224
|
|
|
@@ -204,7 +237,7 @@ import { XPath } from 'xslt-processor'
|
|
|
204
237
|
const xPath = new XPath();
|
|
205
238
|
```
|
|
206
239
|
|
|
207
|
-
`XPath` class is an external dependency, [living in its own repository](https://github.com/DesignLiquido/xpath).
|
|
240
|
+
`XPath` class is an external dependency, [living in its own repository](https://github.com/DesignLiquido/xpath).
|
|
208
241
|
|
|
209
242
|
## Introduction
|
|
210
243
|
|
|
@@ -215,13 +248,40 @@ XSLT-processor builds on Google's [AJAXSLT](https://github.com/4031651/ajaxslt)
|
|
|
215
248
|
|
|
216
249
|
This implementation of XSLT operates at the DOM level on its input documents. It internally uses a DOM implementation to create the output document, but usually returns the output document as text stream. The DOM to construct the output document can be supplied by the application, or else an internal minimal DOM implementation is used. This DOM comes with a minimal XML parser that can be used to generate a suitable DOM representation of the input documents if they are present as text.
|
|
217
250
|
|
|
251
|
+
## Building from source
|
|
252
|
+
|
|
253
|
+
The XPath engine lives in a Git submodule at `src/xpath/lib`. A regular `git clone` does **not** fetch it automatically, so the build will fail unless the submodule is initialised.
|
|
254
|
+
|
|
255
|
+
### Fresh clone
|
|
256
|
+
|
|
257
|
+
```sh
|
|
258
|
+
git clone --recurse-submodules https://github.com/DesignLiquido/xslt-processor.git
|
|
259
|
+
cd xslt-processor
|
|
260
|
+
yarn install
|
|
261
|
+
yarn build
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Already cloned without submodules
|
|
265
|
+
|
|
266
|
+
```sh
|
|
267
|
+
git submodule update --init --recursive
|
|
268
|
+
yarn install
|
|
269
|
+
yarn build
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Updating the submodule to the latest commit
|
|
273
|
+
|
|
274
|
+
```sh
|
|
275
|
+
git submodule update --remote src/xpath/lib
|
|
276
|
+
```
|
|
277
|
+
|
|
218
278
|
## Tests and usage examples
|
|
219
279
|
|
|
220
|
-
New tests are written in Jest
|
|
280
|
+
New tests are written in Jest and can be run by calling: `yarn test`.
|
|
221
281
|
|
|
222
282
|
The files `xslt.html` and `xpath.html` in the directory `interactive-tests` are interactive tests. They can be run directly from the file system; no HTTP server is needed.
|
|
223
283
|
|
|
224
|
-
Both interactive tests and automatic tests demonstrate the use of the library functions.
|
|
284
|
+
Both interactive tests and automatic tests demonstrate the use of the library functions.
|
|
225
285
|
|
|
226
286
|
## Conformance
|
|
227
287
|
|
|
@@ -233,9 +293,9 @@ So far, we have implemented XQuery functions for versions 1.0 and 2.0, but this
|
|
|
233
293
|
|
|
234
294
|
The DOM implementation is minimal so as to support the XSLT processing, and not intended to be complete.
|
|
235
295
|
|
|
236
|
-
The implementation is all agnostic about namespaces. It just expects XSLT elements to have tags that carry the `xsl:` prefix, but we disregard all namespace
|
|
296
|
+
The implementation is all agnostic about namespaces. It just expects XSLT elements to have tags that carry the `xsl:` prefix, but we disregard all namespace declarations for them.
|
|
237
297
|
|
|
238
|
-
[There are a few nonstandard XPath functions](https://github.com/search?q=repo%3ADesignLiquido%2Fxslt-processor%20ext-&type=code).
|
|
298
|
+
[There are a few nonstandard XPath functions](https://github.com/search?q=repo%3ADesignLiquido%2Fxslt-processor%20ext-&type=code).
|
|
239
299
|
|
|
240
300
|
### HTML Conformance
|
|
241
301
|
|
package/index.d.mts
CHANGED
|
@@ -172,6 +172,7 @@ type XsltOptions = {
|
|
|
172
172
|
selfClosingTags: boolean;
|
|
173
173
|
outputMethod?: 'xml' | 'html' | 'text' | 'xhtml' | 'json' | 'adaptive';
|
|
174
174
|
parameters?: XsltParameter[];
|
|
175
|
+
fetchFunction?: (uri: string) => Promise<string>;
|
|
175
176
|
};
|
|
176
177
|
|
|
177
178
|
interface NodeValue {
|
|
@@ -760,6 +761,12 @@ declare class Xslt {
|
|
|
760
761
|
options: XsltOptions;
|
|
761
762
|
decimalFormatSettings: XsltDecimalFormatSettings;
|
|
762
763
|
warningsCallback: (...args: any[]) => void;
|
|
764
|
+
/**
|
|
765
|
+
* Custom fetch function for loading external resources (e.g. xsl:import, xsl:include).
|
|
766
|
+
* Takes a URI and returns the fetched content as a string.
|
|
767
|
+
* Defaults to using the global `fetch` API.
|
|
768
|
+
*/
|
|
769
|
+
fetchFunction: (uri: string) => Promise<string>;
|
|
763
770
|
outputDocument: XDocument;
|
|
764
771
|
outputMethod: 'xml' | 'html' | 'text' | 'name' | 'xhtml' | 'json' | 'adaptive';
|
|
765
772
|
outputOmitXmlDeclaration: string;
|
package/index.d.ts
CHANGED
|
@@ -172,6 +172,7 @@ type XsltOptions = {
|
|
|
172
172
|
selfClosingTags: boolean;
|
|
173
173
|
outputMethod?: 'xml' | 'html' | 'text' | 'xhtml' | 'json' | 'adaptive';
|
|
174
174
|
parameters?: XsltParameter[];
|
|
175
|
+
fetchFunction?: (uri: string) => Promise<string>;
|
|
175
176
|
};
|
|
176
177
|
|
|
177
178
|
interface NodeValue {
|
|
@@ -760,6 +761,12 @@ declare class Xslt {
|
|
|
760
761
|
options: XsltOptions;
|
|
761
762
|
decimalFormatSettings: XsltDecimalFormatSettings;
|
|
762
763
|
warningsCallback: (...args: any[]) => void;
|
|
764
|
+
/**
|
|
765
|
+
* Custom fetch function for loading external resources (e.g. xsl:import, xsl:include).
|
|
766
|
+
* Takes a URI and returns the fetched content as a string.
|
|
767
|
+
* Defaults to using the global `fetch` API.
|
|
768
|
+
*/
|
|
769
|
+
fetchFunction: (uri: string) => Promise<string>;
|
|
763
770
|
outputDocument: XDocument;
|
|
764
771
|
outputMethod: 'xml' | 'html' | 'text' | 'name' | 'xhtml' | 'json' | 'adaptive';
|
|
765
772
|
outputOmitXmlDeclaration: string;
|
package/index.js
CHANGED
|
@@ -10973,7 +10973,7 @@ function xmlElementLogicTrivial(node, buffer, options) {
|
|
|
10973
10973
|
if (!attribute) {
|
|
10974
10974
|
continue;
|
|
10975
10975
|
}
|
|
10976
|
-
if (options.outputMethod === "html" &&
|
|
10976
|
+
if (options.outputMethod === "html" && attribute.nodeName === "xmlns" && attribute.nodeValue === "http://www.w3.org/1999/xhtml") {
|
|
10977
10977
|
continue;
|
|
10978
10978
|
}
|
|
10979
10979
|
if (attribute.nodeName && attribute.nodeValue !== null && attribute.nodeValue !== void 0) {
|
|
@@ -13908,6 +13908,16 @@ var Xslt = class {
|
|
|
13908
13908
|
this.firstTemplateRan = false;
|
|
13909
13909
|
this.forwardsCompatible = false;
|
|
13910
13910
|
this.warningsCallback = console.warn.bind(console);
|
|
13911
|
+
this.fetchFunction = options.fetchFunction || ((uri) => __async(this, null, function* () {
|
|
13912
|
+
const globalFetch = typeof globalThis !== "undefined" && typeof globalThis.fetch === "function" ? globalThis.fetch : null;
|
|
13913
|
+
if (!globalFetch) {
|
|
13914
|
+
throw new Error(
|
|
13915
|
+
"No global fetch implementation available. Please provide options.fetchFunction or use a runtime that exposes globalThis.fetch."
|
|
13916
|
+
);
|
|
13917
|
+
}
|
|
13918
|
+
const response = yield globalFetch(uri);
|
|
13919
|
+
return response.text();
|
|
13920
|
+
}));
|
|
13911
13921
|
this.streamingProcessor = new StreamingProcessor({
|
|
13912
13922
|
xPath: this.xPath,
|
|
13913
13923
|
version: ""
|
|
@@ -14572,6 +14582,19 @@ var Xslt = class {
|
|
|
14572
14582
|
const value = xmlValueLegacyBehavior(documentFragment);
|
|
14573
14583
|
if (output) {
|
|
14574
14584
|
domSetAttribute(output, name, value);
|
|
14585
|
+
if (name.includes(":")) {
|
|
14586
|
+
const prefix = name.split(":")[0];
|
|
14587
|
+
if (prefix !== "xmlns") {
|
|
14588
|
+
const explicitNs = xmlGetAttribute(template, "namespace");
|
|
14589
|
+
const nsUri = explicitNs || this.resolveNamespaceUriForPrefix(template, prefix);
|
|
14590
|
+
if (nsUri) {
|
|
14591
|
+
const nsAttr = `xmlns:${prefix}`;
|
|
14592
|
+
if (!this.isNamespaceDeclaredOnAncestor(output, nsAttr, nsUri)) {
|
|
14593
|
+
domSetAttribute(output, nsAttr, nsUri);
|
|
14594
|
+
}
|
|
14595
|
+
}
|
|
14596
|
+
}
|
|
14597
|
+
}
|
|
14575
14598
|
}
|
|
14576
14599
|
});
|
|
14577
14600
|
}
|
|
@@ -14674,6 +14697,12 @@ var Xslt = class {
|
|
|
14674
14697
|
domAppendChild(destination, node);
|
|
14675
14698
|
} else if (source.nodeType == DOM_ATTRIBUTE_NODE) {
|
|
14676
14699
|
domSetAttribute(destination, source.nodeName, source.nodeValue);
|
|
14700
|
+
if (source.prefix && source.namespaceUri && source.prefix !== "xmlns" && !source.nodeName.startsWith("xmlns")) {
|
|
14701
|
+
const nsAttr = `xmlns:${source.prefix}`;
|
|
14702
|
+
if (!this.isNamespaceDeclaredOnAncestor(destination, nsAttr, source.namespaceUri)) {
|
|
14703
|
+
domSetAttribute(destination, nsAttr, source.namespaceUri);
|
|
14704
|
+
}
|
|
14705
|
+
}
|
|
14677
14706
|
}
|
|
14678
14707
|
return null;
|
|
14679
14708
|
}
|
|
@@ -15341,16 +15370,6 @@ var Xslt = class {
|
|
|
15341
15370
|
xsltImportOrInclude(context, template, output, isImport) {
|
|
15342
15371
|
return __async(this, null, function* () {
|
|
15343
15372
|
const elementName = isImport ? "xsl:import" : "xsl:include";
|
|
15344
|
-
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
15345
|
-
if (major <= 17 && minor < 5) {
|
|
15346
|
-
throw new Error(`Your Node.js version does not support \`<${elementName}>\`. If possible, please update your Node.js version to at least version 17.5.0.`);
|
|
15347
|
-
}
|
|
15348
|
-
if (!global.globalThis.fetch) {
|
|
15349
|
-
global.globalThis.fetch = fetch;
|
|
15350
|
-
global.globalThis.Headers = Headers;
|
|
15351
|
-
global.globalThis.Request = Request;
|
|
15352
|
-
global.globalThis.Response = Response;
|
|
15353
|
-
}
|
|
15354
15373
|
const hrefAttributeFind = template.childNodes.filter((n) => n.nodeName === "href");
|
|
15355
15374
|
if (hrefAttributeFind.length <= 0) {
|
|
15356
15375
|
throw new Error(`<${elementName}> with no href attribute defined.`);
|
|
@@ -15360,8 +15379,7 @@ var Xslt = class {
|
|
|
15360
15379
|
if (this.importedStylesheets.has(href)) {
|
|
15361
15380
|
return;
|
|
15362
15381
|
}
|
|
15363
|
-
const
|
|
15364
|
-
const fetchResponse = yield fetchTest.text();
|
|
15382
|
+
const fetchResponse = yield this.fetchFunction(href);
|
|
15365
15383
|
const includedXslt = this.xmlParser.xmlParse(fetchResponse);
|
|
15366
15384
|
const currentDepth = this.styleSheetStack.length > 0 ? this.styleSheetStack[this.styleSheetStack.length - 1].importDepth : 0;
|
|
15367
15385
|
const metadata = {
|
|
@@ -17608,6 +17626,12 @@ var Xslt = class {
|
|
|
17608
17626
|
const name = attribute.nodeName;
|
|
17609
17627
|
const value = this.xsltAttributeValue(attribute.nodeValue, elementContext);
|
|
17610
17628
|
domSetAttribute(newNode, name, value);
|
|
17629
|
+
if (attribute.prefix && attribute.namespaceUri && attribute.prefix !== "xmlns" && !attribute.nodeName.startsWith("xmlns")) {
|
|
17630
|
+
const nsAttr = `xmlns:${attribute.prefix}`;
|
|
17631
|
+
if (!this.isNamespaceDeclaredOnAncestor(newNode, nsAttr, attribute.namespaceUri)) {
|
|
17632
|
+
domSetAttribute(newNode, nsAttr, attribute.namespaceUri);
|
|
17633
|
+
}
|
|
17634
|
+
}
|
|
17611
17635
|
}
|
|
17612
17636
|
break;
|
|
17613
17637
|
default:
|