xslt-processor 4.8.3 → 4.8.5

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 CHANGED
@@ -719,6 +719,11 @@ declare class MatchResolver {
719
719
  private relativeXsltMatch;
720
720
  }
721
721
 
722
+ interface WhitespacePattern {
723
+ namespaceUri: string | null;
724
+ localName: string;
725
+ isWildcard: boolean;
726
+ }
722
727
  /**
723
728
  * The main class for XSL-T processing.
724
729
  *
@@ -775,13 +780,13 @@ declare class Xslt {
775
780
  * List of element name patterns from xsl:strip-space declarations.
776
781
  * Whitespace-only text nodes inside matching elements will be stripped.
777
782
  */
778
- stripSpacePatterns: string[];
783
+ stripSpacePatterns: WhitespacePattern[];
779
784
  /**
780
785
  * List of element name patterns from xsl:preserve-space declarations.
781
786
  * Whitespace-only text nodes inside matching elements will be preserved.
782
787
  * preserve-space takes precedence over strip-space for conflicting patterns.
783
788
  */
784
- preserveSpacePatterns: string[];
789
+ preserveSpacePatterns: WhitespacePattern[];
785
790
  /**
786
791
  * Namespace aliases from xsl:namespace-alias declarations.
787
792
  * Maps stylesheet namespace prefixes to result namespace prefixes.
@@ -1346,6 +1351,9 @@ declare class Xslt {
1346
1351
  * @todo case-order is not implemented.
1347
1352
  */
1348
1353
  protected xsltSort(context: ExprContext, template: XNode): void;
1354
+ private resolveNamespaceUriForPrefix;
1355
+ private isNamespaceDeclaredOnAncestor;
1356
+ private parseWhitespacePattern;
1349
1357
  /**
1350
1358
  * Implements `xsl:strip-space`.
1351
1359
  * Collects element name patterns for which whitespace-only text nodes should be stripped.
@@ -1378,7 +1386,7 @@ declare class Xslt {
1378
1386
  * @param element The element node (for namespace checking).
1379
1387
  * @returns True if the element matches the pattern.
1380
1388
  */
1381
- protected matchesNamePattern(elementName: string, pattern: string, element: XNode): boolean;
1389
+ protected matchesNamePattern(elementName: string, pattern: WhitespacePattern, element: XNode): boolean;
1382
1390
  /**
1383
1391
  * Implements `xsl:template`.
1384
1392
  * @param context The Expression Context.
package/index.d.ts CHANGED
@@ -719,6 +719,11 @@ declare class MatchResolver {
719
719
  private relativeXsltMatch;
720
720
  }
721
721
 
722
+ interface WhitespacePattern {
723
+ namespaceUri: string | null;
724
+ localName: string;
725
+ isWildcard: boolean;
726
+ }
722
727
  /**
723
728
  * The main class for XSL-T processing.
724
729
  *
@@ -775,13 +780,13 @@ declare class Xslt {
775
780
  * List of element name patterns from xsl:strip-space declarations.
776
781
  * Whitespace-only text nodes inside matching elements will be stripped.
777
782
  */
778
- stripSpacePatterns: string[];
783
+ stripSpacePatterns: WhitespacePattern[];
779
784
  /**
780
785
  * List of element name patterns from xsl:preserve-space declarations.
781
786
  * Whitespace-only text nodes inside matching elements will be preserved.
782
787
  * preserve-space takes precedence over strip-space for conflicting patterns.
783
788
  */
784
- preserveSpacePatterns: string[];
789
+ preserveSpacePatterns: WhitespacePattern[];
785
790
  /**
786
791
  * Namespace aliases from xsl:namespace-alias declarations.
787
792
  * Maps stylesheet namespace prefixes to result namespace prefixes.
@@ -1346,6 +1351,9 @@ declare class Xslt {
1346
1351
  * @todo case-order is not implemented.
1347
1352
  */
1348
1353
  protected xsltSort(context: ExprContext, template: XNode): void;
1354
+ private resolveNamespaceUriForPrefix;
1355
+ private isNamespaceDeclaredOnAncestor;
1356
+ private parseWhitespacePattern;
1349
1357
  /**
1350
1358
  * Implements `xsl:strip-space`.
1351
1359
  * Collects element name patterns for which whitespace-only text nodes should be stripped.
@@ -1378,7 +1386,7 @@ declare class Xslt {
1378
1386
  * @param element The element node (for namespace checking).
1379
1387
  * @returns True if the element matches the pattern.
1380
1388
  */
1381
- protected matchesNamePattern(elementName: string, pattern: string, element: XNode): boolean;
1389
+ protected matchesNamePattern(elementName: string, pattern: WhitespacePattern, element: XNode): boolean;
1382
1390
  /**
1383
1391
  * Implements `xsl:template`.
1384
1392
  * @param context The Expression Context.
package/index.js CHANGED
@@ -9028,9 +9028,13 @@ var XPathBaseParser = class {
9028
9028
  return expr;
9029
9029
  }
9030
9030
  parsePrimaryExpr() {
9031
- var _a, _b;
9031
+ var _a, _b, _c;
9032
9032
  if (this.match("DOLLAR")) {
9033
- const name = this.consume("IDENTIFIER", "Expected variable name after $").lexeme;
9033
+ const next = this.peek();
9034
+ if (!next || !this.isNcNameToken(next.type)) {
9035
+ throw grammarViolation(`Expected variable name after $. Got: ${(_a = next == null ? void 0 : next.lexeme) != null ? _a : "EOF"}`);
9036
+ }
9037
+ const name = this.advance().lexeme;
9034
9038
  return new XPathVariableReference(name);
9035
9039
  }
9036
9040
  if (this.match("OPEN_PAREN")) {
@@ -9054,7 +9058,7 @@ var XPathBaseParser = class {
9054
9058
  return this.parseFunctionCall();
9055
9059
  }
9056
9060
  throw grammarViolation(
9057
- `Unexpected token in primary expression: ${(_b = (_a = this.peek()) == null ? void 0 : _a.lexeme) != null ? _b : "EOF"}`
9061
+ `Unexpected token in primary expression: ${(_c = (_b = this.peek()) == null ? void 0 : _b.lexeme) != null ? _c : "EOF"}`
9058
9062
  );
9059
9063
  }
9060
9064
  parseFunctionCall() {
@@ -10969,6 +10973,9 @@ function xmlElementLogicTrivial(node, buffer, options) {
10969
10973
  if (!attribute) {
10970
10974
  continue;
10971
10975
  }
10976
+ if (options.outputMethod === "html" && (attribute.nodeName === "xmlns" || attribute.nodeName.startsWith("xmlns:"))) {
10977
+ continue;
10978
+ }
10972
10979
  if (attribute.nodeName && attribute.nodeValue !== null && attribute.nodeValue !== void 0) {
10973
10980
  buffer.push(` ${xmlFullNodeName(attribute)}="${xmlEscapeAttr(attribute.nodeValue)}"`);
10974
10981
  }
@@ -14471,7 +14478,40 @@ var Xslt = class {
14471
14478
  } = currentTemplateContext;
14472
14479
  const currentNode = context.nodeList[context.position];
14473
14480
  const top = template.ownerDocument.documentElement;
14474
- const allTemplates = collectAndExpandTemplates(top, currentMode, this.xPath, this.templateSourceMap);
14481
+ const stylesheetRoots = [];
14482
+ if (top) {
14483
+ stylesheetRoots.push(top);
14484
+ }
14485
+ this.importedStylesheets.forEach((doc) => {
14486
+ if (!doc) {
14487
+ return;
14488
+ }
14489
+ if (doc.nodeType === DOM_DOCUMENT_NODE) {
14490
+ const rootElement = doc.childNodes.find(
14491
+ (child) => child.nodeType === DOM_ELEMENT_NODE
14492
+ );
14493
+ if (rootElement) {
14494
+ stylesheetRoots.push(rootElement);
14495
+ }
14496
+ } else if (doc.nodeType === DOM_ELEMENT_NODE) {
14497
+ stylesheetRoots.push(doc);
14498
+ }
14499
+ });
14500
+ let allTemplates = [];
14501
+ let docOrderOffset = 0;
14502
+ for (const root2 of stylesheetRoots) {
14503
+ const templates = collectAndExpandTemplates(
14504
+ root2,
14505
+ currentMode,
14506
+ this.xPath,
14507
+ this.templateSourceMap
14508
+ );
14509
+ for (const templateEntry of templates) {
14510
+ templateEntry.documentOrder += docOrderOffset;
14511
+ }
14512
+ docOrderOffset += templates.length;
14513
+ allTemplates = allTemplates.concat(templates);
14514
+ }
14475
14515
  const importedTemplates = allTemplates.filter((t) => {
14476
14516
  const metadata2 = this.templateSourceMap.get(t.template);
14477
14517
  return metadata2 && metadata2.importDepth > currentDepth;
@@ -14607,7 +14647,11 @@ var Xslt = class {
14607
14647
  if (source.nodeType == DOM_ELEMENT_NODE) {
14608
14648
  let node = domCreateElement(this.outputDocument, source.nodeName);
14609
14649
  if (source.namespaceUri !== null && source.namespaceUri !== void 0) {
14610
- domSetAttribute(node, "xmlns", source.namespaceUri);
14650
+ const prefix = source.prefix || (source.nodeName.includes(":") ? source.nodeName.split(":")[0] : null);
14651
+ const nsAttr = prefix ? `xmlns:${prefix}` : "xmlns";
14652
+ if (!this.isNamespaceDeclaredOnAncestor(destination, nsAttr, source.namespaceUri)) {
14653
+ domSetAttribute(node, nsAttr, source.namespaceUri);
14654
+ }
14611
14655
  }
14612
14656
  node.siblingPosition = destination.childNodes.length;
14613
14657
  domAppendChild(destination, node);
@@ -16350,6 +16394,17 @@ var Xslt = class {
16350
16394
  * @returns The formatted number string.
16351
16395
  */
16352
16396
  xsltFormatNumber(number, format, groupingSeparator, groupingSize) {
16397
+ if (format.match(/^0+1$/)) {
16398
+ const width = format.length;
16399
+ let result2 = number.toString().padStart(width, "0");
16400
+ if (groupingSeparator && groupingSize) {
16401
+ const size = parseInt(groupingSize, 10);
16402
+ if (size > 0 && !isNaN(size)) {
16403
+ result2 = this.applyGrouping(result2, groupingSeparator, size);
16404
+ }
16405
+ }
16406
+ return result2;
16407
+ }
16353
16408
  const formatChar = format.charAt(0);
16354
16409
  let result;
16355
16410
  switch (formatChar) {
@@ -16478,6 +16533,54 @@ var Xslt = class {
16478
16533
  }
16479
16534
  this.xPath.xPathSort(context, sort2);
16480
16535
  }
16536
+ resolveNamespaceUriForPrefix(node, prefix) {
16537
+ const attrName = prefix ? `xmlns:${prefix}` : "xmlns";
16538
+ let current = node;
16539
+ while (current) {
16540
+ const attributes = current.childNodes.filter(
16541
+ (child) => child.nodeType === DOM_ATTRIBUTE_NODE
16542
+ );
16543
+ for (const attribute of attributes) {
16544
+ if (attribute.nodeName === attrName) {
16545
+ return attribute.nodeValue;
16546
+ }
16547
+ if (prefix && attribute.prefix === "xmlns" && attribute.localName === prefix) {
16548
+ return attribute.nodeValue;
16549
+ }
16550
+ if (!prefix && attribute.nodeName === "xmlns") {
16551
+ return attribute.nodeValue;
16552
+ }
16553
+ }
16554
+ current = current.parentNode;
16555
+ }
16556
+ return null;
16557
+ }
16558
+ isNamespaceDeclaredOnAncestor(node, nsAttr, nsUri) {
16559
+ let current = node;
16560
+ while (current) {
16561
+ const value = domGetAttributeValue(current, nsAttr);
16562
+ if (value === nsUri) {
16563
+ return true;
16564
+ }
16565
+ current = current.parentNode;
16566
+ }
16567
+ return false;
16568
+ }
16569
+ parseWhitespacePattern(pattern, template) {
16570
+ if (pattern === "*") {
16571
+ return { namespaceUri: null, localName: "*", isWildcard: true };
16572
+ }
16573
+ if (pattern.includes(":")) {
16574
+ const [prefix, localPart] = pattern.split(":");
16575
+ const namespaceUri = this.resolveNamespaceUriForPrefix(template, prefix);
16576
+ return {
16577
+ namespaceUri: namespaceUri != null ? namespaceUri : null,
16578
+ localName: localPart || "*",
16579
+ isWildcard: localPart === "*"
16580
+ };
16581
+ }
16582
+ return { namespaceUri: null, localName: pattern, isWildcard: false };
16583
+ }
16481
16584
  /**
16482
16585
  * Implements `xsl:strip-space`.
16483
16586
  * Collects element name patterns for which whitespace-only text nodes should be stripped.
@@ -16487,7 +16590,9 @@ var Xslt = class {
16487
16590
  const elements = xmlGetAttribute(template, "elements");
16488
16591
  if (elements) {
16489
16592
  const patterns = elements.trim().split(/\s+/);
16490
- this.stripSpacePatterns.push(...patterns);
16593
+ for (const pattern of patterns) {
16594
+ this.stripSpacePatterns.push(this.parseWhitespacePattern(pattern, template));
16595
+ }
16491
16596
  }
16492
16597
  }
16493
16598
  /**
@@ -16500,7 +16605,9 @@ var Xslt = class {
16500
16605
  const elements = xmlGetAttribute(template, "elements");
16501
16606
  if (elements) {
16502
16607
  const patterns = elements.trim().split(/\s+/);
16503
- this.preserveSpacePatterns.push(...patterns);
16608
+ for (const pattern of patterns) {
16609
+ this.preserveSpacePatterns.push(this.parseWhitespacePattern(pattern, template));
16610
+ }
16504
16611
  }
16505
16612
  }
16506
16613
  /**
@@ -16557,19 +16664,19 @@ var Xslt = class {
16557
16664
  * @returns True if the element matches the pattern.
16558
16665
  */
16559
16666
  matchesNamePattern(elementName, pattern, element) {
16560
- if (pattern === "*") {
16561
- return true;
16562
- }
16563
- if (pattern.includes(":")) {
16564
- const [prefix, localPart] = pattern.split(":");
16565
- const elementPrefix = element.prefix || "";
16566
- if (localPart === "*") {
16567
- return elementPrefix === prefix;
16568
- } else {
16569
- return elementPrefix === prefix && elementName === localPart;
16667
+ var _a;
16668
+ const elementNamespace = (_a = element.namespaceUri) != null ? _a : this.resolveNamespaceUriForPrefix(element, element.prefix || null);
16669
+ if (pattern.namespaceUri !== null) {
16670
+ if (elementNamespace !== pattern.namespaceUri) {
16671
+ return false;
16570
16672
  }
16673
+ } else if (!pattern.isWildcard && elementNamespace) {
16674
+ return false;
16675
+ }
16676
+ if (pattern.isWildcard) {
16677
+ return true;
16571
16678
  }
16572
- return elementName === pattern;
16679
+ return elementName === pattern.localName;
16573
16680
  }
16574
16681
  /**
16575
16682
  * Implements `xsl:template`.
@@ -17455,9 +17562,38 @@ var Xslt = class {
17455
17562
  let elementContext = context;
17456
17563
  node = context.nodeList[context.position];
17457
17564
  let newNode;
17458
- newNode = domCreateElement(this.outputDocument, template.nodeName);
17565
+ let qualifiedName = template.nodeName;
17566
+ let namespaceUri = template.namespaceUri;
17567
+ const templatePrefix = template.prefix || "";
17568
+ const aliasPrefix = this.namespaceAliases.get(templatePrefix);
17569
+ if (aliasPrefix) {
17570
+ const localName = template.localName || template.nodeName;
17571
+ if (aliasPrefix === "#default") {
17572
+ qualifiedName = localName;
17573
+ namespaceUri = this.resolveNamespaceUriForPrefix(template, null);
17574
+ } else {
17575
+ qualifiedName = `${aliasPrefix}:${localName}`;
17576
+ namespaceUri = this.resolveNamespaceUriForPrefix(template, aliasPrefix);
17577
+ }
17578
+ }
17579
+ newNode = domCreateElement(this.outputDocument, qualifiedName);
17459
17580
  newNode.siblingPosition = (output || this.outputDocument).childNodes.length;
17460
17581
  domAppendChild(output || this.outputDocument, newNode);
17582
+ if (aliasPrefix) {
17583
+ if (aliasPrefix === "#default") {
17584
+ if (namespaceUri) {
17585
+ domSetAttribute(newNode, "xmlns", namespaceUri);
17586
+ }
17587
+ } else if (namespaceUri) {
17588
+ domSetAttribute(newNode, `xmlns:${aliasPrefix}`, namespaceUri);
17589
+ }
17590
+ } else if (namespaceUri) {
17591
+ const prefix = templatePrefix || (qualifiedName.includes(":") ? qualifiedName.split(":")[0] : null);
17592
+ const nsAttr = prefix ? `xmlns:${prefix}` : "xmlns";
17593
+ if (!this.isNamespaceDeclaredOnAncestor(output, nsAttr, namespaceUri)) {
17594
+ domSetAttribute(newNode, nsAttr, namespaceUri);
17595
+ }
17596
+ }
17461
17597
  const useAttributeSetsAttr = template.childNodes.find(
17462
17598
  (a) => (a == null ? void 0 : a.nodeType) === DOM_ATTRIBUTE_NODE && a.nodeName === "use-attribute-sets"
17463
17599
  );