xslt-processor 4.8.4 → 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 +18 -3
- package/index.d.ts +18 -3
- package/index.js +184 -28
- package/index.js.map +1 -1
- package/index.mjs +184 -28
- 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 {
|
|
@@ -719,6 +720,11 @@ declare class MatchResolver {
|
|
|
719
720
|
private relativeXsltMatch;
|
|
720
721
|
}
|
|
721
722
|
|
|
723
|
+
interface WhitespacePattern {
|
|
724
|
+
namespaceUri: string | null;
|
|
725
|
+
localName: string;
|
|
726
|
+
isWildcard: boolean;
|
|
727
|
+
}
|
|
722
728
|
/**
|
|
723
729
|
* The main class for XSL-T processing.
|
|
724
730
|
*
|
|
@@ -755,6 +761,12 @@ declare class Xslt {
|
|
|
755
761
|
options: XsltOptions;
|
|
756
762
|
decimalFormatSettings: XsltDecimalFormatSettings;
|
|
757
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>;
|
|
758
770
|
outputDocument: XDocument;
|
|
759
771
|
outputMethod: 'xml' | 'html' | 'text' | 'name' | 'xhtml' | 'json' | 'adaptive';
|
|
760
772
|
outputOmitXmlDeclaration: string;
|
|
@@ -775,13 +787,13 @@ declare class Xslt {
|
|
|
775
787
|
* List of element name patterns from xsl:strip-space declarations.
|
|
776
788
|
* Whitespace-only text nodes inside matching elements will be stripped.
|
|
777
789
|
*/
|
|
778
|
-
stripSpacePatterns:
|
|
790
|
+
stripSpacePatterns: WhitespacePattern[];
|
|
779
791
|
/**
|
|
780
792
|
* List of element name patterns from xsl:preserve-space declarations.
|
|
781
793
|
* Whitespace-only text nodes inside matching elements will be preserved.
|
|
782
794
|
* preserve-space takes precedence over strip-space for conflicting patterns.
|
|
783
795
|
*/
|
|
784
|
-
preserveSpacePatterns:
|
|
796
|
+
preserveSpacePatterns: WhitespacePattern[];
|
|
785
797
|
/**
|
|
786
798
|
* Namespace aliases from xsl:namespace-alias declarations.
|
|
787
799
|
* Maps stylesheet namespace prefixes to result namespace prefixes.
|
|
@@ -1346,6 +1358,9 @@ declare class Xslt {
|
|
|
1346
1358
|
* @todo case-order is not implemented.
|
|
1347
1359
|
*/
|
|
1348
1360
|
protected xsltSort(context: ExprContext, template: XNode): void;
|
|
1361
|
+
private resolveNamespaceUriForPrefix;
|
|
1362
|
+
private isNamespaceDeclaredOnAncestor;
|
|
1363
|
+
private parseWhitespacePattern;
|
|
1349
1364
|
/**
|
|
1350
1365
|
* Implements `xsl:strip-space`.
|
|
1351
1366
|
* Collects element name patterns for which whitespace-only text nodes should be stripped.
|
|
@@ -1378,7 +1393,7 @@ declare class Xslt {
|
|
|
1378
1393
|
* @param element The element node (for namespace checking).
|
|
1379
1394
|
* @returns True if the element matches the pattern.
|
|
1380
1395
|
*/
|
|
1381
|
-
protected matchesNamePattern(elementName: string, pattern:
|
|
1396
|
+
protected matchesNamePattern(elementName: string, pattern: WhitespacePattern, element: XNode): boolean;
|
|
1382
1397
|
/**
|
|
1383
1398
|
* Implements `xsl:template`.
|
|
1384
1399
|
* @param context The Expression Context.
|
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 {
|
|
@@ -719,6 +720,11 @@ declare class MatchResolver {
|
|
|
719
720
|
private relativeXsltMatch;
|
|
720
721
|
}
|
|
721
722
|
|
|
723
|
+
interface WhitespacePattern {
|
|
724
|
+
namespaceUri: string | null;
|
|
725
|
+
localName: string;
|
|
726
|
+
isWildcard: boolean;
|
|
727
|
+
}
|
|
722
728
|
/**
|
|
723
729
|
* The main class for XSL-T processing.
|
|
724
730
|
*
|
|
@@ -755,6 +761,12 @@ declare class Xslt {
|
|
|
755
761
|
options: XsltOptions;
|
|
756
762
|
decimalFormatSettings: XsltDecimalFormatSettings;
|
|
757
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>;
|
|
758
770
|
outputDocument: XDocument;
|
|
759
771
|
outputMethod: 'xml' | 'html' | 'text' | 'name' | 'xhtml' | 'json' | 'adaptive';
|
|
760
772
|
outputOmitXmlDeclaration: string;
|
|
@@ -775,13 +787,13 @@ declare class Xslt {
|
|
|
775
787
|
* List of element name patterns from xsl:strip-space declarations.
|
|
776
788
|
* Whitespace-only text nodes inside matching elements will be stripped.
|
|
777
789
|
*/
|
|
778
|
-
stripSpacePatterns:
|
|
790
|
+
stripSpacePatterns: WhitespacePattern[];
|
|
779
791
|
/**
|
|
780
792
|
* List of element name patterns from xsl:preserve-space declarations.
|
|
781
793
|
* Whitespace-only text nodes inside matching elements will be preserved.
|
|
782
794
|
* preserve-space takes precedence over strip-space for conflicting patterns.
|
|
783
795
|
*/
|
|
784
|
-
preserveSpacePatterns:
|
|
796
|
+
preserveSpacePatterns: WhitespacePattern[];
|
|
785
797
|
/**
|
|
786
798
|
* Namespace aliases from xsl:namespace-alias declarations.
|
|
787
799
|
* Maps stylesheet namespace prefixes to result namespace prefixes.
|
|
@@ -1346,6 +1358,9 @@ declare class Xslt {
|
|
|
1346
1358
|
* @todo case-order is not implemented.
|
|
1347
1359
|
*/
|
|
1348
1360
|
protected xsltSort(context: ExprContext, template: XNode): void;
|
|
1361
|
+
private resolveNamespaceUriForPrefix;
|
|
1362
|
+
private isNamespaceDeclaredOnAncestor;
|
|
1363
|
+
private parseWhitespacePattern;
|
|
1349
1364
|
/**
|
|
1350
1365
|
* Implements `xsl:strip-space`.
|
|
1351
1366
|
* Collects element name patterns for which whitespace-only text nodes should be stripped.
|
|
@@ -1378,7 +1393,7 @@ declare class Xslt {
|
|
|
1378
1393
|
* @param element The element node (for namespace checking).
|
|
1379
1394
|
* @returns True if the element matches the pattern.
|
|
1380
1395
|
*/
|
|
1381
|
-
protected matchesNamePattern(elementName: string, pattern:
|
|
1396
|
+
protected matchesNamePattern(elementName: string, pattern: WhitespacePattern, element: XNode): boolean;
|
|
1382
1397
|
/**
|
|
1383
1398
|
* Implements `xsl:template`.
|
|
1384
1399
|
* @param context The Expression Context.
|
package/index.js
CHANGED
|
@@ -10973,6 +10973,9 @@ function xmlElementLogicTrivial(node, buffer, options) {
|
|
|
10973
10973
|
if (!attribute) {
|
|
10974
10974
|
continue;
|
|
10975
10975
|
}
|
|
10976
|
+
if (options.outputMethod === "html" && attribute.nodeName === "xmlns" && attribute.nodeValue === "http://www.w3.org/1999/xhtml") {
|
|
10977
|
+
continue;
|
|
10978
|
+
}
|
|
10976
10979
|
if (attribute.nodeName && attribute.nodeValue !== null && attribute.nodeValue !== void 0) {
|
|
10977
10980
|
buffer.push(` ${xmlFullNodeName(attribute)}="${xmlEscapeAttr(attribute.nodeValue)}"`);
|
|
10978
10981
|
}
|
|
@@ -13905,6 +13908,16 @@ var Xslt = class {
|
|
|
13905
13908
|
this.firstTemplateRan = false;
|
|
13906
13909
|
this.forwardsCompatible = false;
|
|
13907
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
|
+
}));
|
|
13908
13921
|
this.streamingProcessor = new StreamingProcessor({
|
|
13909
13922
|
xPath: this.xPath,
|
|
13910
13923
|
version: ""
|
|
@@ -14475,7 +14488,40 @@ var Xslt = class {
|
|
|
14475
14488
|
} = currentTemplateContext;
|
|
14476
14489
|
const currentNode = context.nodeList[context.position];
|
|
14477
14490
|
const top = template.ownerDocument.documentElement;
|
|
14478
|
-
const
|
|
14491
|
+
const stylesheetRoots = [];
|
|
14492
|
+
if (top) {
|
|
14493
|
+
stylesheetRoots.push(top);
|
|
14494
|
+
}
|
|
14495
|
+
this.importedStylesheets.forEach((doc) => {
|
|
14496
|
+
if (!doc) {
|
|
14497
|
+
return;
|
|
14498
|
+
}
|
|
14499
|
+
if (doc.nodeType === DOM_DOCUMENT_NODE) {
|
|
14500
|
+
const rootElement = doc.childNodes.find(
|
|
14501
|
+
(child) => child.nodeType === DOM_ELEMENT_NODE
|
|
14502
|
+
);
|
|
14503
|
+
if (rootElement) {
|
|
14504
|
+
stylesheetRoots.push(rootElement);
|
|
14505
|
+
}
|
|
14506
|
+
} else if (doc.nodeType === DOM_ELEMENT_NODE) {
|
|
14507
|
+
stylesheetRoots.push(doc);
|
|
14508
|
+
}
|
|
14509
|
+
});
|
|
14510
|
+
let allTemplates = [];
|
|
14511
|
+
let docOrderOffset = 0;
|
|
14512
|
+
for (const root2 of stylesheetRoots) {
|
|
14513
|
+
const templates = collectAndExpandTemplates(
|
|
14514
|
+
root2,
|
|
14515
|
+
currentMode,
|
|
14516
|
+
this.xPath,
|
|
14517
|
+
this.templateSourceMap
|
|
14518
|
+
);
|
|
14519
|
+
for (const templateEntry of templates) {
|
|
14520
|
+
templateEntry.documentOrder += docOrderOffset;
|
|
14521
|
+
}
|
|
14522
|
+
docOrderOffset += templates.length;
|
|
14523
|
+
allTemplates = allTemplates.concat(templates);
|
|
14524
|
+
}
|
|
14479
14525
|
const importedTemplates = allTemplates.filter((t) => {
|
|
14480
14526
|
const metadata2 = this.templateSourceMap.get(t.template);
|
|
14481
14527
|
return metadata2 && metadata2.importDepth > currentDepth;
|
|
@@ -14536,6 +14582,19 @@ var Xslt = class {
|
|
|
14536
14582
|
const value = xmlValueLegacyBehavior(documentFragment);
|
|
14537
14583
|
if (output) {
|
|
14538
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
|
+
}
|
|
14539
14598
|
}
|
|
14540
14599
|
});
|
|
14541
14600
|
}
|
|
@@ -14611,7 +14670,11 @@ var Xslt = class {
|
|
|
14611
14670
|
if (source.nodeType == DOM_ELEMENT_NODE) {
|
|
14612
14671
|
let node = domCreateElement(this.outputDocument, source.nodeName);
|
|
14613
14672
|
if (source.namespaceUri !== null && source.namespaceUri !== void 0) {
|
|
14614
|
-
|
|
14673
|
+
const prefix = source.prefix || (source.nodeName.includes(":") ? source.nodeName.split(":")[0] : null);
|
|
14674
|
+
const nsAttr = prefix ? `xmlns:${prefix}` : "xmlns";
|
|
14675
|
+
if (!this.isNamespaceDeclaredOnAncestor(destination, nsAttr, source.namespaceUri)) {
|
|
14676
|
+
domSetAttribute(node, nsAttr, source.namespaceUri);
|
|
14677
|
+
}
|
|
14615
14678
|
}
|
|
14616
14679
|
node.siblingPosition = destination.childNodes.length;
|
|
14617
14680
|
domAppendChild(destination, node);
|
|
@@ -14634,6 +14697,12 @@ var Xslt = class {
|
|
|
14634
14697
|
domAppendChild(destination, node);
|
|
14635
14698
|
} else if (source.nodeType == DOM_ATTRIBUTE_NODE) {
|
|
14636
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
|
+
}
|
|
14637
14706
|
}
|
|
14638
14707
|
return null;
|
|
14639
14708
|
}
|
|
@@ -15301,16 +15370,6 @@ var Xslt = class {
|
|
|
15301
15370
|
xsltImportOrInclude(context, template, output, isImport) {
|
|
15302
15371
|
return __async(this, null, function* () {
|
|
15303
15372
|
const elementName = isImport ? "xsl:import" : "xsl:include";
|
|
15304
|
-
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
15305
|
-
if (major <= 17 && minor < 5) {
|
|
15306
|
-
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.`);
|
|
15307
|
-
}
|
|
15308
|
-
if (!global.globalThis.fetch) {
|
|
15309
|
-
global.globalThis.fetch = fetch;
|
|
15310
|
-
global.globalThis.Headers = Headers;
|
|
15311
|
-
global.globalThis.Request = Request;
|
|
15312
|
-
global.globalThis.Response = Response;
|
|
15313
|
-
}
|
|
15314
15373
|
const hrefAttributeFind = template.childNodes.filter((n) => n.nodeName === "href");
|
|
15315
15374
|
if (hrefAttributeFind.length <= 0) {
|
|
15316
15375
|
throw new Error(`<${elementName}> with no href attribute defined.`);
|
|
@@ -15320,8 +15379,7 @@ var Xslt = class {
|
|
|
15320
15379
|
if (this.importedStylesheets.has(href)) {
|
|
15321
15380
|
return;
|
|
15322
15381
|
}
|
|
15323
|
-
const
|
|
15324
|
-
const fetchResponse = yield fetchTest.text();
|
|
15382
|
+
const fetchResponse = yield this.fetchFunction(href);
|
|
15325
15383
|
const includedXslt = this.xmlParser.xmlParse(fetchResponse);
|
|
15326
15384
|
const currentDepth = this.styleSheetStack.length > 0 ? this.styleSheetStack[this.styleSheetStack.length - 1].importDepth : 0;
|
|
15327
15385
|
const metadata = {
|
|
@@ -16354,6 +16412,17 @@ var Xslt = class {
|
|
|
16354
16412
|
* @returns The formatted number string.
|
|
16355
16413
|
*/
|
|
16356
16414
|
xsltFormatNumber(number, format, groupingSeparator, groupingSize) {
|
|
16415
|
+
if (format.match(/^0+1$/)) {
|
|
16416
|
+
const width = format.length;
|
|
16417
|
+
let result2 = number.toString().padStart(width, "0");
|
|
16418
|
+
if (groupingSeparator && groupingSize) {
|
|
16419
|
+
const size = parseInt(groupingSize, 10);
|
|
16420
|
+
if (size > 0 && !isNaN(size)) {
|
|
16421
|
+
result2 = this.applyGrouping(result2, groupingSeparator, size);
|
|
16422
|
+
}
|
|
16423
|
+
}
|
|
16424
|
+
return result2;
|
|
16425
|
+
}
|
|
16357
16426
|
const formatChar = format.charAt(0);
|
|
16358
16427
|
let result;
|
|
16359
16428
|
switch (formatChar) {
|
|
@@ -16482,6 +16551,54 @@ var Xslt = class {
|
|
|
16482
16551
|
}
|
|
16483
16552
|
this.xPath.xPathSort(context, sort2);
|
|
16484
16553
|
}
|
|
16554
|
+
resolveNamespaceUriForPrefix(node, prefix) {
|
|
16555
|
+
const attrName = prefix ? `xmlns:${prefix}` : "xmlns";
|
|
16556
|
+
let current = node;
|
|
16557
|
+
while (current) {
|
|
16558
|
+
const attributes = current.childNodes.filter(
|
|
16559
|
+
(child) => child.nodeType === DOM_ATTRIBUTE_NODE
|
|
16560
|
+
);
|
|
16561
|
+
for (const attribute of attributes) {
|
|
16562
|
+
if (attribute.nodeName === attrName) {
|
|
16563
|
+
return attribute.nodeValue;
|
|
16564
|
+
}
|
|
16565
|
+
if (prefix && attribute.prefix === "xmlns" && attribute.localName === prefix) {
|
|
16566
|
+
return attribute.nodeValue;
|
|
16567
|
+
}
|
|
16568
|
+
if (!prefix && attribute.nodeName === "xmlns") {
|
|
16569
|
+
return attribute.nodeValue;
|
|
16570
|
+
}
|
|
16571
|
+
}
|
|
16572
|
+
current = current.parentNode;
|
|
16573
|
+
}
|
|
16574
|
+
return null;
|
|
16575
|
+
}
|
|
16576
|
+
isNamespaceDeclaredOnAncestor(node, nsAttr, nsUri) {
|
|
16577
|
+
let current = node;
|
|
16578
|
+
while (current) {
|
|
16579
|
+
const value = domGetAttributeValue(current, nsAttr);
|
|
16580
|
+
if (value === nsUri) {
|
|
16581
|
+
return true;
|
|
16582
|
+
}
|
|
16583
|
+
current = current.parentNode;
|
|
16584
|
+
}
|
|
16585
|
+
return false;
|
|
16586
|
+
}
|
|
16587
|
+
parseWhitespacePattern(pattern, template) {
|
|
16588
|
+
if (pattern === "*") {
|
|
16589
|
+
return { namespaceUri: null, localName: "*", isWildcard: true };
|
|
16590
|
+
}
|
|
16591
|
+
if (pattern.includes(":")) {
|
|
16592
|
+
const [prefix, localPart] = pattern.split(":");
|
|
16593
|
+
const namespaceUri = this.resolveNamespaceUriForPrefix(template, prefix);
|
|
16594
|
+
return {
|
|
16595
|
+
namespaceUri: namespaceUri != null ? namespaceUri : null,
|
|
16596
|
+
localName: localPart || "*",
|
|
16597
|
+
isWildcard: localPart === "*"
|
|
16598
|
+
};
|
|
16599
|
+
}
|
|
16600
|
+
return { namespaceUri: null, localName: pattern, isWildcard: false };
|
|
16601
|
+
}
|
|
16485
16602
|
/**
|
|
16486
16603
|
* Implements `xsl:strip-space`.
|
|
16487
16604
|
* Collects element name patterns for which whitespace-only text nodes should be stripped.
|
|
@@ -16491,7 +16608,9 @@ var Xslt = class {
|
|
|
16491
16608
|
const elements = xmlGetAttribute(template, "elements");
|
|
16492
16609
|
if (elements) {
|
|
16493
16610
|
const patterns = elements.trim().split(/\s+/);
|
|
16494
|
-
|
|
16611
|
+
for (const pattern of patterns) {
|
|
16612
|
+
this.stripSpacePatterns.push(this.parseWhitespacePattern(pattern, template));
|
|
16613
|
+
}
|
|
16495
16614
|
}
|
|
16496
16615
|
}
|
|
16497
16616
|
/**
|
|
@@ -16504,7 +16623,9 @@ var Xslt = class {
|
|
|
16504
16623
|
const elements = xmlGetAttribute(template, "elements");
|
|
16505
16624
|
if (elements) {
|
|
16506
16625
|
const patterns = elements.trim().split(/\s+/);
|
|
16507
|
-
|
|
16626
|
+
for (const pattern of patterns) {
|
|
16627
|
+
this.preserveSpacePatterns.push(this.parseWhitespacePattern(pattern, template));
|
|
16628
|
+
}
|
|
16508
16629
|
}
|
|
16509
16630
|
}
|
|
16510
16631
|
/**
|
|
@@ -16561,19 +16682,19 @@ var Xslt = class {
|
|
|
16561
16682
|
* @returns True if the element matches the pattern.
|
|
16562
16683
|
*/
|
|
16563
16684
|
matchesNamePattern(elementName, pattern, element) {
|
|
16564
|
-
|
|
16565
|
-
|
|
16566
|
-
|
|
16567
|
-
|
|
16568
|
-
|
|
16569
|
-
const elementPrefix = element.prefix || "";
|
|
16570
|
-
if (localPart === "*") {
|
|
16571
|
-
return elementPrefix === prefix;
|
|
16572
|
-
} else {
|
|
16573
|
-
return elementPrefix === prefix && elementName === localPart;
|
|
16685
|
+
var _a;
|
|
16686
|
+
const elementNamespace = (_a = element.namespaceUri) != null ? _a : this.resolveNamespaceUriForPrefix(element, element.prefix || null);
|
|
16687
|
+
if (pattern.namespaceUri !== null) {
|
|
16688
|
+
if (elementNamespace !== pattern.namespaceUri) {
|
|
16689
|
+
return false;
|
|
16574
16690
|
}
|
|
16691
|
+
} else if (!pattern.isWildcard && elementNamespace) {
|
|
16692
|
+
return false;
|
|
16693
|
+
}
|
|
16694
|
+
if (pattern.isWildcard) {
|
|
16695
|
+
return true;
|
|
16575
16696
|
}
|
|
16576
|
-
return elementName === pattern;
|
|
16697
|
+
return elementName === pattern.localName;
|
|
16577
16698
|
}
|
|
16578
16699
|
/**
|
|
16579
16700
|
* Implements `xsl:template`.
|
|
@@ -17459,9 +17580,38 @@ var Xslt = class {
|
|
|
17459
17580
|
let elementContext = context;
|
|
17460
17581
|
node = context.nodeList[context.position];
|
|
17461
17582
|
let newNode;
|
|
17462
|
-
|
|
17583
|
+
let qualifiedName = template.nodeName;
|
|
17584
|
+
let namespaceUri = template.namespaceUri;
|
|
17585
|
+
const templatePrefix = template.prefix || "";
|
|
17586
|
+
const aliasPrefix = this.namespaceAliases.get(templatePrefix);
|
|
17587
|
+
if (aliasPrefix) {
|
|
17588
|
+
const localName = template.localName || template.nodeName;
|
|
17589
|
+
if (aliasPrefix === "#default") {
|
|
17590
|
+
qualifiedName = localName;
|
|
17591
|
+
namespaceUri = this.resolveNamespaceUriForPrefix(template, null);
|
|
17592
|
+
} else {
|
|
17593
|
+
qualifiedName = `${aliasPrefix}:${localName}`;
|
|
17594
|
+
namespaceUri = this.resolveNamespaceUriForPrefix(template, aliasPrefix);
|
|
17595
|
+
}
|
|
17596
|
+
}
|
|
17597
|
+
newNode = domCreateElement(this.outputDocument, qualifiedName);
|
|
17463
17598
|
newNode.siblingPosition = (output || this.outputDocument).childNodes.length;
|
|
17464
17599
|
domAppendChild(output || this.outputDocument, newNode);
|
|
17600
|
+
if (aliasPrefix) {
|
|
17601
|
+
if (aliasPrefix === "#default") {
|
|
17602
|
+
if (namespaceUri) {
|
|
17603
|
+
domSetAttribute(newNode, "xmlns", namespaceUri);
|
|
17604
|
+
}
|
|
17605
|
+
} else if (namespaceUri) {
|
|
17606
|
+
domSetAttribute(newNode, `xmlns:${aliasPrefix}`, namespaceUri);
|
|
17607
|
+
}
|
|
17608
|
+
} else if (namespaceUri) {
|
|
17609
|
+
const prefix = templatePrefix || (qualifiedName.includes(":") ? qualifiedName.split(":")[0] : null);
|
|
17610
|
+
const nsAttr = prefix ? `xmlns:${prefix}` : "xmlns";
|
|
17611
|
+
if (!this.isNamespaceDeclaredOnAncestor(output, nsAttr, namespaceUri)) {
|
|
17612
|
+
domSetAttribute(newNode, nsAttr, namespaceUri);
|
|
17613
|
+
}
|
|
17614
|
+
}
|
|
17465
17615
|
const useAttributeSetsAttr = template.childNodes.find(
|
|
17466
17616
|
(a) => (a == null ? void 0 : a.nodeType) === DOM_ATTRIBUTE_NODE && a.nodeName === "use-attribute-sets"
|
|
17467
17617
|
);
|
|
@@ -17476,6 +17626,12 @@ var Xslt = class {
|
|
|
17476
17626
|
const name = attribute.nodeName;
|
|
17477
17627
|
const value = this.xsltAttributeValue(attribute.nodeValue, elementContext);
|
|
17478
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
|
+
}
|
|
17479
17635
|
}
|
|
17480
17636
|
break;
|
|
17481
17637
|
default:
|