xslt-processor 4.3.0 → 4.3.1
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/index.d.mts +16 -4
- package/index.d.ts +16 -4
- package/index.js +188 -52
- package/index.js.map +1 -1
- package/index.mjs +188 -52
- package/index.mjs.map +1 -1
- package/package.json +1 -1
- package/umd/xslt-processor.global.js +3 -3
- package/umd/xslt-processor.global.js.map +1 -1
package/index.mjs
CHANGED
|
@@ -706,12 +706,12 @@ var XPathStep = class extends XPathExpression {
|
|
|
706
706
|
if (!nsUri) {
|
|
707
707
|
return false;
|
|
708
708
|
}
|
|
709
|
-
const
|
|
709
|
+
const nodeLocalName2 = node.localName || node.nodeName && this.extractLocalName(node.nodeName);
|
|
710
710
|
const nodeNsUri = node.namespaceURI || node.namespaceUri || "";
|
|
711
|
-
return
|
|
711
|
+
return nodeLocalName2 === localName && nodeNsUri === nsUri;
|
|
712
712
|
}
|
|
713
|
-
const
|
|
714
|
-
return
|
|
713
|
+
const nodeLocalName = node.localName || this.extractLocalName(node.nodeName);
|
|
714
|
+
return nodeLocalName === testName;
|
|
715
715
|
case "node-type":
|
|
716
716
|
switch (this.nodeTest.nodeType) {
|
|
717
717
|
case "node":
|
|
@@ -770,6 +770,17 @@ var XPathStep = class extends XPathExpression {
|
|
|
770
770
|
if (Array.isArray(value)) return value.length > 0;
|
|
771
771
|
return !!value;
|
|
772
772
|
}
|
|
773
|
+
/**
|
|
774
|
+
* Extract the local name from a qualified name (e.g., "ns:name" -> "name", "name" -> "name")
|
|
775
|
+
*/
|
|
776
|
+
extractLocalName(qname) {
|
|
777
|
+
if (!qname) return "";
|
|
778
|
+
const colonIndex = qname.indexOf(":");
|
|
779
|
+
if (colonIndex > 0) {
|
|
780
|
+
return qname.substring(colonIndex + 1);
|
|
781
|
+
}
|
|
782
|
+
return qname;
|
|
783
|
+
}
|
|
773
784
|
};
|
|
774
785
|
|
|
775
786
|
// src/xpath/lib/src/expressions/predicate-expression.ts
|
|
@@ -1054,7 +1065,7 @@ var XPathFunctionCall = class extends XPathExpression {
|
|
|
1054
1065
|
namespaceUri(args, context) {
|
|
1055
1066
|
var _a;
|
|
1056
1067
|
const node = this.getNodeArg(args, context);
|
|
1057
|
-
return (_a = node == null ? void 0 : node.
|
|
1068
|
+
return (_a = node == null ? void 0 : node.namespaceUri) != null ? _a : "";
|
|
1058
1069
|
}
|
|
1059
1070
|
nodeName(args, context) {
|
|
1060
1071
|
var _a;
|
|
@@ -1524,6 +1535,7 @@ var _XNode = class _XNode {
|
|
|
1524
1535
|
this.childNodes = [];
|
|
1525
1536
|
this.visited = false;
|
|
1526
1537
|
this.escape = true;
|
|
1538
|
+
this.fromXslText = false;
|
|
1527
1539
|
this.siblingPosition = -1;
|
|
1528
1540
|
this.init(type, name, opt_value, opt_owner, opt_namespace);
|
|
1529
1541
|
}
|
|
@@ -2050,23 +2062,32 @@ function xmlTransformedTextRecursive(node, buffer, options) {
|
|
|
2050
2062
|
const nodeType = node.nodeType;
|
|
2051
2063
|
const nodeValue = node.nodeValue;
|
|
2052
2064
|
if (nodeType === DOM_TEXT_NODE) {
|
|
2053
|
-
|
|
2065
|
+
const isFromXslText = node.fromXslText === true;
|
|
2066
|
+
if (node.nodeValue && (isFromXslText || node.nodeValue.trim() !== "")) {
|
|
2054
2067
|
const finalText = node.escape && options.escape ? xmlEscapeText(node.nodeValue) : xmlUnescapeText(node.nodeValue);
|
|
2055
2068
|
buffer.push(finalText);
|
|
2056
2069
|
}
|
|
2057
2070
|
} else if (nodeType === DOM_CDATA_SECTION_NODE) {
|
|
2058
|
-
if (options.
|
|
2071
|
+
if (options.outputMethod === "text") {
|
|
2072
|
+
buffer.push(nodeValue);
|
|
2073
|
+
} else if (options.cData) {
|
|
2059
2074
|
buffer.push(xmlEscapeText(nodeValue));
|
|
2060
2075
|
} else {
|
|
2061
2076
|
buffer.push(`<![CDATA[${nodeValue}]]>`);
|
|
2062
2077
|
}
|
|
2063
2078
|
} else if (nodeType == DOM_COMMENT_NODE) {
|
|
2064
|
-
|
|
2079
|
+
if (options.outputMethod !== "text") {
|
|
2080
|
+
buffer.push(`<!-- ${nodeValue} -->`);
|
|
2081
|
+
}
|
|
2065
2082
|
} else if (nodeType == DOM_ELEMENT_NODE) {
|
|
2066
|
-
if (
|
|
2067
|
-
|
|
2083
|
+
if (options.outputMethod === "text") {
|
|
2084
|
+
xmlElementLogicTextOnly(node, buffer, options);
|
|
2068
2085
|
} else {
|
|
2069
|
-
|
|
2086
|
+
if (node.nodeName !== null && node.nodeName !== void 0) {
|
|
2087
|
+
xmlElementLogicTrivial(node, buffer, options);
|
|
2088
|
+
} else {
|
|
2089
|
+
xmlElementLogicMuted(node, buffer, options);
|
|
2090
|
+
}
|
|
2070
2091
|
}
|
|
2071
2092
|
} else if (nodeType === DOM_DOCUMENT_NODE || nodeType === DOM_DOCUMENT_FRAGMENT_NODE) {
|
|
2072
2093
|
let childNodes = node.firstChild ? [] : node.childNodes;
|
|
@@ -2154,6 +2175,22 @@ function xmlElementLogicMuted(node, buffer, options) {
|
|
|
2154
2175
|
xmlTransformedTextRecursive(childNodes[i], buffer, options);
|
|
2155
2176
|
}
|
|
2156
2177
|
}
|
|
2178
|
+
function xmlElementLogicTextOnly(node, buffer, options) {
|
|
2179
|
+
let childNodes = [];
|
|
2180
|
+
if (node.firstChild) {
|
|
2181
|
+
let child = node.firstChild;
|
|
2182
|
+
while (child) {
|
|
2183
|
+
childNodes.push(child);
|
|
2184
|
+
child = child.nextSibling;
|
|
2185
|
+
}
|
|
2186
|
+
} else {
|
|
2187
|
+
childNodes = node.childNodes;
|
|
2188
|
+
}
|
|
2189
|
+
childNodes = childNodes.sort((a, b) => a.siblingPosition - b.siblingPosition);
|
|
2190
|
+
for (let i = 0; i < childNodes.length; ++i) {
|
|
2191
|
+
xmlTransformedTextRecursive(childNodes[i], buffer, options);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2157
2194
|
function xmlFullNodeName(node) {
|
|
2158
2195
|
const nodeName = node.nodeName;
|
|
2159
2196
|
if (node.prefix && nodeName.indexOf(`${node.prefix}:`) != 0) {
|
|
@@ -2261,6 +2298,41 @@ function nodeToJsonObject(node) {
|
|
|
2261
2298
|
}
|
|
2262
2299
|
return null;
|
|
2263
2300
|
}
|
|
2301
|
+
function detectAdaptiveOutputFormat(node) {
|
|
2302
|
+
if (!node) {
|
|
2303
|
+
return "xml";
|
|
2304
|
+
}
|
|
2305
|
+
const nodeType = node.nodeType;
|
|
2306
|
+
if (nodeType === DOM_DOCUMENT_NODE || nodeType === DOM_DOCUMENT_FRAGMENT_NODE) {
|
|
2307
|
+
const children = node.childNodes || [];
|
|
2308
|
+
let elementCount = 0;
|
|
2309
|
+
let textCount = 0;
|
|
2310
|
+
let hasSignificantText = false;
|
|
2311
|
+
for (let i = 0; i < children.length; i++) {
|
|
2312
|
+
const child = children[i];
|
|
2313
|
+
if (child.nodeType === DOM_ELEMENT_NODE) {
|
|
2314
|
+
elementCount++;
|
|
2315
|
+
} else if (child.nodeType === DOM_TEXT_NODE) {
|
|
2316
|
+
const text = child.nodeValue ? child.nodeValue.trim() : "";
|
|
2317
|
+
if (text.length > 0) {
|
|
2318
|
+
textCount++;
|
|
2319
|
+
hasSignificantText = true;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
if (elementCount === 0 && hasSignificantText) {
|
|
2324
|
+
return "text";
|
|
2325
|
+
}
|
|
2326
|
+
return "xml";
|
|
2327
|
+
}
|
|
2328
|
+
if (nodeType === DOM_TEXT_NODE || nodeType === DOM_CDATA_SECTION_NODE) {
|
|
2329
|
+
const text = node.nodeValue ? node.nodeValue.trim() : "";
|
|
2330
|
+
if (text.length > 0) {
|
|
2331
|
+
return "text";
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
return "xml";
|
|
2335
|
+
}
|
|
2264
2336
|
function xmlToJson(node) {
|
|
2265
2337
|
if (!node) {
|
|
2266
2338
|
return "{}";
|
|
@@ -2537,7 +2609,7 @@ var XmlParser = class {
|
|
|
2537
2609
|
} else if (!tag && char === "<") {
|
|
2538
2610
|
let text = xml.slice(start, i);
|
|
2539
2611
|
if (text && parent !== root) {
|
|
2540
|
-
domAppendChild(parent, domCreateTextNode(xmlDocument, text));
|
|
2612
|
+
domAppendChild(parent, domCreateTextNode(xmlDocument, he2.decode(text)));
|
|
2541
2613
|
}
|
|
2542
2614
|
if (xml.slice(i + 1, i + 4) === "!--") {
|
|
2543
2615
|
let endTagIndex = xml.slice(i + 4).indexOf("-->");
|
|
@@ -2681,15 +2753,6 @@ var NodeConverter = class {
|
|
|
2681
2753
|
adaptXNode(node) {
|
|
2682
2754
|
if (!node) return null;
|
|
2683
2755
|
const adapted = node;
|
|
2684
|
-
if (!("namespaceURI" in adapted)) {
|
|
2685
|
-
Object.defineProperty(adapted, "namespaceURI", {
|
|
2686
|
-
get() {
|
|
2687
|
-
return this.namespaceUri;
|
|
2688
|
-
},
|
|
2689
|
-
enumerable: true,
|
|
2690
|
-
configurable: true
|
|
2691
|
-
});
|
|
2692
|
-
}
|
|
2693
2756
|
if (!("textContent" in adapted)) {
|
|
2694
2757
|
Object.defineProperty(adapted, "textContent", {
|
|
2695
2758
|
get() {
|
|
@@ -3657,7 +3720,7 @@ var Xslt = class {
|
|
|
3657
3720
|
* The exported entry point of the XSL-T processor.
|
|
3658
3721
|
* @param xmlDoc The input document root, as DOM node.
|
|
3659
3722
|
* @param stylesheet The stylesheet document root, as DOM node.
|
|
3660
|
-
* @returns the processed document, as XML text in a string,
|
|
3723
|
+
* @returns the processed document, as XML text in a string, JSON string if outputMethod is 'json', or text if outputMethod is 'text' or 'adaptive' (with text content).
|
|
3661
3724
|
*/
|
|
3662
3725
|
xsltProcess(xmlDoc, stylesheet) {
|
|
3663
3726
|
return __async(this, null, function* () {
|
|
@@ -3673,11 +3736,15 @@ var Xslt = class {
|
|
|
3673
3736
|
if (this.outputMethod === "json") {
|
|
3674
3737
|
return xmlToJson(outputDocument);
|
|
3675
3738
|
}
|
|
3739
|
+
let outputMethod = this.outputMethod;
|
|
3740
|
+
if (this.outputMethod === "adaptive") {
|
|
3741
|
+
outputMethod = detectAdaptiveOutputFormat(outputDocument);
|
|
3742
|
+
}
|
|
3676
3743
|
const transformedOutputXml = xmlTransformedText(outputDocument, {
|
|
3677
3744
|
cData: this.options.cData,
|
|
3678
3745
|
escape: this.options.escape,
|
|
3679
3746
|
selfClosingTags: this.options.selfClosingTags,
|
|
3680
|
-
outputMethod
|
|
3747
|
+
outputMethod
|
|
3681
3748
|
});
|
|
3682
3749
|
return transformedOutputXml;
|
|
3683
3750
|
});
|
|
@@ -3838,6 +3905,9 @@ var Xslt = class {
|
|
|
3838
3905
|
for (let j = 0; j < modifiedContext.contextSize(); ++j) {
|
|
3839
3906
|
const currentNode = modifiedContext.nodeList[j];
|
|
3840
3907
|
if (currentNode.nodeType === DOM_TEXT_NODE) {
|
|
3908
|
+
if (!this.xsltPassText(currentNode)) {
|
|
3909
|
+
continue;
|
|
3910
|
+
}
|
|
3841
3911
|
const textNodeContext = context.clone(
|
|
3842
3912
|
[currentNode],
|
|
3843
3913
|
0
|
|
@@ -4606,6 +4676,7 @@ var Xslt = class {
|
|
|
4606
4676
|
xsltText(context, template, output) {
|
|
4607
4677
|
const text = xmlValue(template);
|
|
4608
4678
|
const node = domCreateTextNode(this.outputDocument, text);
|
|
4679
|
+
node.fromXslText = true;
|
|
4609
4680
|
const disableOutputEscaping = template.childNodes.filter(
|
|
4610
4681
|
(a) => a.nodeType === DOM_ATTRIBUTE_NODE && a.nodeName === "disable-output-escaping"
|
|
4611
4682
|
);
|
|
@@ -4613,8 +4684,80 @@ var Xslt = class {
|
|
|
4613
4684
|
node.escape = false;
|
|
4614
4685
|
}
|
|
4615
4686
|
const destinationTextNode = output || this.outputDocument;
|
|
4687
|
+
node.siblingPosition = destinationTextNode.childNodes.length;
|
|
4616
4688
|
destinationTextNode.appendChild(node);
|
|
4617
4689
|
}
|
|
4690
|
+
/**
|
|
4691
|
+
* Validates XSLT stylesheet/transform attributes.
|
|
4692
|
+
* According to XSLT specification, validates:
|
|
4693
|
+
* - Required version attribute
|
|
4694
|
+
* - Valid version values (1.0, 2.0, 3.0)
|
|
4695
|
+
* - Valid namespace declarations
|
|
4696
|
+
* - Valid values for optional attributes (extension-element-prefixes, exclude-result-prefixes)
|
|
4697
|
+
* @param stylesheetElement The `<xsl:stylesheet>` or `<xsl:transform>` element to validate.
|
|
4698
|
+
* @param context The Expression Context for namespace access.
|
|
4699
|
+
*/
|
|
4700
|
+
validateStylesheetAttributes(stylesheetElement, context) {
|
|
4701
|
+
const attributes = stylesheetElement.childNodes.filter((n) => n.nodeType === DOM_ATTRIBUTE_NODE);
|
|
4702
|
+
const validAttributes = ["version", "id", "extension-element-prefixes", "exclude-result-prefixes", "default-collation"];
|
|
4703
|
+
const validNamespaceAttributes = ["xmlns"];
|
|
4704
|
+
let versionFound = false;
|
|
4705
|
+
for (let attribute of attributes) {
|
|
4706
|
+
const nodeName = attribute.nodeName;
|
|
4707
|
+
const nodeValue = attribute.nodeValue;
|
|
4708
|
+
if (attribute.prefix === "xmlns") {
|
|
4709
|
+
context.knownNamespaces[attribute.localName] = nodeValue;
|
|
4710
|
+
continue;
|
|
4711
|
+
}
|
|
4712
|
+
if (nodeName === "xmlns") {
|
|
4713
|
+
context.knownNamespaces[""] = nodeValue;
|
|
4714
|
+
continue;
|
|
4715
|
+
}
|
|
4716
|
+
if (nodeName === "version") {
|
|
4717
|
+
versionFound = true;
|
|
4718
|
+
if (!["1.0", "2.0", "3.0"].includes(nodeValue)) {
|
|
4719
|
+
throw new Error(
|
|
4720
|
+
`XSLT version not defined or invalid. Actual resolved version: ${nodeValue || "(none)"}.`
|
|
4721
|
+
);
|
|
4722
|
+
}
|
|
4723
|
+
this.version = nodeValue;
|
|
4724
|
+
context.xsltVersion = nodeValue;
|
|
4725
|
+
continue;
|
|
4726
|
+
}
|
|
4727
|
+
if (nodeName === "extension-element-prefixes") {
|
|
4728
|
+
const prefixes = nodeValue.split(/\s+/);
|
|
4729
|
+
for (const prefix of prefixes) {
|
|
4730
|
+
if (prefix && !/^[a-zA-Z_:][\w:.-]*$/.test(prefix)) {
|
|
4731
|
+
throw new Error(`Invalid prefix in extension-element-prefixes: "${prefix}". Prefixes must be valid QNames.`);
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
continue;
|
|
4735
|
+
}
|
|
4736
|
+
if (nodeName === "exclude-result-prefixes") {
|
|
4737
|
+
if (nodeValue !== "#all") {
|
|
4738
|
+
const prefixes = nodeValue.split(/\s+/);
|
|
4739
|
+
for (const prefix of prefixes) {
|
|
4740
|
+
if (prefix && !/^[a-zA-Z_:][\w:.-]*$/.test(prefix)) {
|
|
4741
|
+
throw new Error(`Invalid prefix in exclude-result-prefixes: "${prefix}". Prefixes must be valid QNames or "#all".`);
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
}
|
|
4745
|
+
continue;
|
|
4746
|
+
}
|
|
4747
|
+
if (nodeName === "default-collation") {
|
|
4748
|
+
if (!nodeValue || nodeValue.trim().length === 0) {
|
|
4749
|
+
throw new Error("The default-collation attribute must contain a URI.");
|
|
4750
|
+
}
|
|
4751
|
+
continue;
|
|
4752
|
+
}
|
|
4753
|
+
if (nodeName === "id") {
|
|
4754
|
+
if (!/^[a-zA-Z_:][\w:.-]*$/.test(nodeValue)) {
|
|
4755
|
+
throw new Error(`Invalid id attribute value: "${nodeValue}". IDs must be valid NCNames.`);
|
|
4756
|
+
}
|
|
4757
|
+
continue;
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4618
4761
|
/**
|
|
4619
4762
|
* Implements `<xsl:stylesheet>` and `<xsl:transform>`, and its corresponding
|
|
4620
4763
|
* validations.
|
|
@@ -4625,24 +4768,7 @@ var Xslt = class {
|
|
|
4625
4768
|
*/
|
|
4626
4769
|
xsltTransformOrStylesheet(context, template, output) {
|
|
4627
4770
|
return __async(this, null, function* () {
|
|
4628
|
-
|
|
4629
|
-
switch (stylesheetAttribute.nodeName) {
|
|
4630
|
-
case "version":
|
|
4631
|
-
this.version = stylesheetAttribute.nodeValue;
|
|
4632
|
-
if (!["1.0", "2.0", "3.0"].includes(this.version)) {
|
|
4633
|
-
throw new Error(
|
|
4634
|
-
`XSLT version not defined or invalid. Actual resolved version: ${this.version || "(none)"}.`
|
|
4635
|
-
);
|
|
4636
|
-
}
|
|
4637
|
-
context.xsltVersion = this.version;
|
|
4638
|
-
break;
|
|
4639
|
-
default:
|
|
4640
|
-
if (stylesheetAttribute.prefix === "xmlns") {
|
|
4641
|
-
context.knownNamespaces[stylesheetAttribute.localName] = stylesheetAttribute.nodeValue;
|
|
4642
|
-
}
|
|
4643
|
-
break;
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4771
|
+
this.validateStylesheetAttributes(template, context);
|
|
4646
4772
|
let importsDone = false;
|
|
4647
4773
|
for (const child of template.childNodes) {
|
|
4648
4774
|
if (child.nodeType === DOM_ELEMENT_NODE) {
|
|
@@ -4682,16 +4808,22 @@ var Xslt = class {
|
|
|
4682
4808
|
}
|
|
4683
4809
|
}
|
|
4684
4810
|
if (matchCandidates.length > 0) {
|
|
4685
|
-
matchCandidates.
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4811
|
+
const rootPatternMatch = matchCandidates.find((c) => c.priority.matchPattern === "/");
|
|
4812
|
+
let winner;
|
|
4813
|
+
if (rootPatternMatch) {
|
|
4814
|
+
winner = rootPatternMatch;
|
|
4815
|
+
} else {
|
|
4816
|
+
matchCandidates.sort((a, b) => {
|
|
4817
|
+
if (a.priority.importPrecedence !== b.priority.importPrecedence) {
|
|
4818
|
+
return b.priority.importPrecedence - a.priority.importPrecedence;
|
|
4819
|
+
}
|
|
4820
|
+
if (a.priority.effectivePriority !== b.priority.effectivePriority) {
|
|
4821
|
+
return b.priority.effectivePriority - a.priority.effectivePriority;
|
|
4822
|
+
}
|
|
4823
|
+
return b.priority.documentOrder - a.priority.documentOrder;
|
|
4824
|
+
});
|
|
4825
|
+
winner = matchCandidates[0];
|
|
4826
|
+
}
|
|
4695
4827
|
const conflicts = matchCandidates.filter(
|
|
4696
4828
|
(t) => t.priority.importPrecedence === winner.priority.importPrecedence && t.priority.effectivePriority === winner.priority.effectivePriority
|
|
4697
4829
|
);
|
|
@@ -4829,7 +4961,11 @@ var Xslt = class {
|
|
|
4829
4961
|
return __async(this, null, function* () {
|
|
4830
4962
|
const contextClone = context.clone();
|
|
4831
4963
|
for (let i = 0; i < template.childNodes.length; ++i) {
|
|
4832
|
-
|
|
4964
|
+
const child = template.childNodes[i];
|
|
4965
|
+
if (child.nodeType === DOM_ATTRIBUTE_NODE) {
|
|
4966
|
+
continue;
|
|
4967
|
+
}
|
|
4968
|
+
yield this.xsltProcessContext(contextClone, child, output);
|
|
4833
4969
|
}
|
|
4834
4970
|
});
|
|
4835
4971
|
}
|