diff --git a/README.md b/README.md
index c91e84d..ae03073 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ const xslt = new Xslt();
const xPath = xslt.xPath;
```
-Or ou can import it like this:
+Or you can import it like this:
```js
import { XPath } from 'xslt-processor'
@@ -70,6 +70,8 @@ import { XPath } from 'xslt-processor'
const xPath = new XPath();
```
+`XPath` class is an external dependency, [living in its own repository](https://github.com/DesignLiquido/xpath).
+
If you write pre-2015 JS code, make adjustments as needed.
### `Xslt` class options
@@ -145,76 +147,11 @@ console.log(parsed.root.users.user); // ["Alice", "Bob"]
You can simply add a tag like this:
```html
-
+
```
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).
-### Breaking Changes
-
-#### Version 2
-
-Until version 2.3.1, use like the example below:
-
-```js
-import { Xslt, XmlParser } from 'xslt-processor'
-
-// xmlString: string of xml file contents
-// xsltString: string of xslt file contents
-// outXmlString: output xml string.
-const xslt = new Xslt();
-const xmlParser = new XmlParser();
-const outXmlString = xslt.xsltProcess( // Not async.
- xmlParser.xmlParse(xmlString),
- xmlParser.xmlParse(xsltString)
-);
-```
-
-Version 3 received `` which relies on Fetch API, which is asynchronous. Version 2 doesn't support ``.
-
-If using Node.js older than version v17.5.0, please use version 3.2.3, that uses `node-fetch` package. Versions 3.3.0 onward require at least Node.js version v17.5.0, since they use native `fetch()` function.
-
-#### Version 1
-
-Until version 1.2.8, use like the example below:
-
-```js
-import { Xslt, xmlParse } from 'xslt-processor'
-
-// xmlString: string of xml file contents
-// xsltString: string of xslt file contents
-// outXmlString: output xml string.
-const xslt = new Xslt();
-const outXmlString = xslt.xsltProcess(
- xmlParse(xmlString),
- xmlParse(xsltString)
-);
-```
-
-#### Version 0
-
-Until version 0.11.7, use like the example below:
-
-```js
-import { xsltProcess, xmlParse } from 'xslt-processor'
-
-// xmlString: string of xml file contents
-// xsltString: string of xslt file contents
-// outXmlString: output xml string.
-const outXmlString = xsltProcess(
- xmlParse(xmlString),
- xmlParse(xsltString)
-);
-```
-
-and to access the XPath parser:
-
-```js
-import { xpathParse } from 'xslt-processor'
-```
-
-These functions are part of `Xslt` and `XPath` classes, respectively, at version 1.x onward.
-
## Introduction
XSLT-processor contains an implementation of XSLT in JavaScript. Because XSLT uses XPath, it also contains an implementation of XPath that can be used
@@ -312,6 +249,71 @@ Use `` to preserve whitespace in specific elements, overridi
3. `xsl:strip-space` applies to remaining matches
4. By default (no declarations), whitespace is preserved
+### Breaking Changes
+
+#### Version 2
+
+Until version 2.3.1, use like the example below:
+
+```js
+import { Xslt, XmlParser } from 'xslt-processor'
+
+// xmlString: string of xml file contents
+// xsltString: string of xslt file contents
+// outXmlString: output xml string.
+const xslt = new Xslt();
+const xmlParser = new XmlParser();
+const outXmlString = xslt.xsltProcess( // Not async.
+ xmlParser.xmlParse(xmlString),
+ xmlParser.xmlParse(xsltString)
+);
+```
+
+Version 3 received `` which relies on Fetch API, which is asynchronous. Version 2 doesn't support ``.
+
+If using Node.js older than version v17.5.0, please use version 3.2.3, that uses `node-fetch` package. Versions 3.3.0 onward require at least Node.js version v17.5.0, since they use native `fetch()` function.
+
+#### Version 1
+
+Until version 1.2.8, use like the example below:
+
+```js
+import { Xslt, xmlParse } from 'xslt-processor'
+
+// xmlString: string of xml file contents
+// xsltString: string of xslt file contents
+// outXmlString: output xml string.
+const xslt = new Xslt();
+const outXmlString = xslt.xsltProcess(
+ xmlParse(xmlString),
+ xmlParse(xsltString)
+);
+```
+
+#### Version 0
+
+Until version 0.11.7, use like the example below:
+
+```js
+import { xsltProcess, xmlParse } from 'xslt-processor'
+
+// xmlString: string of xml file contents
+// xsltString: string of xslt file contents
+// outXmlString: output xml string.
+const outXmlString = xsltProcess(
+ xmlParse(xmlString),
+ xmlParse(xsltString)
+);
+```
+
+and to access the XPath parser:
+
+```js
+import { xpathParse } from 'xslt-processor'
+```
+
+These functions are part of `Xslt` and `XPath` classes, respectively, at version 1.x onward.
+
## References
- XPath Specification: http://www.w3.org/TR/1999/REC-xpath-19991116
diff --git a/src/dom/functions.ts b/src/dom/functions.ts
index c3be6ad..8f77f60 100644
--- a/src/dom/functions.ts
+++ b/src/dom/functions.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Copyright 2018 Johannes Wilm
// Copyright 2005 Google Inc.
// All Rights Reserved
diff --git a/src/dom/util.ts b/src/dom/util.ts
index 34ba658..c1df578 100644
--- a/src/dom/util.ts
+++ b/src/dom/util.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Copyright 2018 Johannes Wilm
// Copyright 2005 Google
//
diff --git a/src/dom/xmltoken.ts b/src/dom/xmltoken.ts
index 179b27d..1f4bf10 100644
--- a/src/dom/xmltoken.ts
+++ b/src/dom/xmltoken.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Copyright 2018 Johannes Wilm
// Copyright 2006 Google Inc.
// All Rights Reserved
diff --git a/src/xpath/index.ts b/src/xpath/index.ts
index 06f86f7..de28019 100644
--- a/src/xpath/index.ts
+++ b/src/xpath/index.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// XPath implementation exports
// Main XPath class
diff --git a/src/xpath/lib b/src/xpath/lib
index eee689c..baf6329 160000
--- a/src/xpath/lib
+++ b/src/xpath/lib
@@ -1 +1 @@
-Subproject commit eee689c487ff2a67d50fc166541959dd6611711f
+Subproject commit baf632939603e298c579655d00959e29fc66ca13
diff --git a/src/xpath/match-resolver.ts b/src/xpath/match-resolver.ts
index bf3d6c3..1972ced 100644
--- a/src/xpath/match-resolver.ts
+++ b/src/xpath/match-resolver.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Match resolver that works with the new XPath implementation.
import { XNode } from '../dom';
diff --git a/src/xpath/tokens.ts b/src/xpath/tokens.ts
index 1e05e02..10b7688 100644
--- a/src/xpath/tokens.ts
+++ b/src/xpath/tokens.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// XPath tokens and axis constants
// The axes of XPath expressions.
diff --git a/src/xpath/xpath.ts b/src/xpath/xpath.ts
index 9f61599..74e3514 100644
--- a/src/xpath/xpath.ts
+++ b/src/xpath/xpath.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// XPath adapter that uses the new lexer/parser implementation
// while maintaining backward compatibility with the existing XSLT API.
@@ -8,6 +8,7 @@ import { XPathParser } from './lib/src/parser';
import { XPathExpression, XPathLocationPath, XPathUnionExpression } from './lib/src/expressions';
import { XPathContext, XPathResult, createContext } from './lib/src/context';
import { XPathNode } from './lib/src/node';
+import { JsonToXmlConverter } from './lib/src/expressions/json-to-xml-converter';
import { ExprContext } from './expr-context';
import { NodeValue, StringValue, NumberValue, BooleanValue, NodeSetValue } from './values';
@@ -134,6 +135,7 @@ class NodeConverter {
variables: this.convertVariables(exprContext),
functions: this.createCustomFunctions(exprContext),
namespaces: exprContext.knownNamespaces,
+ xsltVersion: exprContext.xsltVersion,
});
}
@@ -202,8 +204,14 @@ class NodeConverter {
*/
xPathNodeToXNode(xpathNode: XPathNode): XNode | null {
if (!xpathNode) return null;
- // The nodes are already XNodes, just cast back
- return xpathNode as unknown as XNode;
+
+ // Check if this is already an XNode (from native parsing)
+ if (xpathNode instanceof XNode) {
+ return xpathNode as unknown as XNode;
+ }
+
+ // Otherwise, convert XPathNode interface (from json-to-xml or xpath/lib) to XNode
+ return this.convertXPathNodeToXNode(xpathNode);
}
/**
@@ -304,9 +312,107 @@ class NodeConverter {
return this.xmlToJson(node);
};
+ // json-to-xml() function - XSLT 3.0 specific
+ functions['json-to-xml'] = (jsonText: any) => {
+ // Check XSLT version - only supported in 3.0
+ if (exprContext.xsltVersion === '1.0') {
+ throw new Error('json-to-xml() is not supported in XSLT 1.0. Use version="3.0" in your stylesheet.');
+ }
+
+ // Handle node set or single value
+ const jsonStr = Array.isArray(jsonText) ? jsonText[0] : jsonText;
+ if (!jsonStr) {
+ return null;
+ }
+
+ // Convert JSON string to XML document node using xpath lib converter
+ const converter = new JsonToXmlConverter();
+ const xpathNode = converter.convert(String(jsonStr));
+
+ if (!xpathNode) {
+ return null;
+ }
+
+ // Get owner document from context
+ const ownerDoc = exprContext.nodeList && exprContext.nodeList.length > 0
+ ? exprContext.nodeList[0].ownerDocument
+ : null;
+
+ // Convert XPathNode interface tree to actual XNode objects
+ const convertedNode = this.convertXPathNodeToXNode(xpathNode, ownerDoc);
+
+ // Return as array for consistency with xpath processor
+ return convertedNode ? [convertedNode] : null;
+ };
+
return functions;
}
+ /**
+ * Convert an XPathNode interface tree to actual XNode objects.
+ * This is needed to convert json-to-xml() output to XSLT-compatible nodes.
+ */
+ private convertXPathNodeToXNode(xpathNode: XPathNode, ownerDoc?: any): XNode | null {
+ if (!xpathNode) {
+ return null;
+ }
+
+ const { XNode: XNodeClass } = require('../dom');
+ const { DOM_DOCUMENT_NODE, DOM_TEXT_NODE, DOM_ELEMENT_NODE } = require('../constants');
+
+ let node: XNode;
+
+ if (xpathNode.nodeType === DOM_DOCUMENT_NODE) {
+ // For document nodes, extract and return the root element
+ if (xpathNode.childNodes && xpathNode.childNodes.length > 0) {
+ const rootChild = xpathNode.childNodes[0] as any;
+ node = this.convertXPathNodeToXNode(rootChild, ownerDoc);
+ return node;
+ }
+ return null;
+ } else if (xpathNode.nodeType === DOM_TEXT_NODE) {
+ // Create a text node
+ const textContent = xpathNode.textContent || '';
+ node = new XNodeClass(
+ DOM_TEXT_NODE,
+ '#text',
+ textContent,
+ ownerDoc
+ );
+ } else {
+ // Element node (DOM_ELEMENT_NODE)
+ node = new XNodeClass(
+ DOM_ELEMENT_NODE,
+ xpathNode.nodeName || 'element',
+ '',
+ ownerDoc
+ );
+
+ // Copy namespace URI if present
+ if (xpathNode.namespaceUri) {
+ node.namespaceUri = xpathNode.namespaceUri;
+ }
+
+ // Recursively convert child nodes
+ if (xpathNode.childNodes && xpathNode.childNodes.length > 0) {
+ for (let i = 0; i < xpathNode.childNodes.length; i++) {
+ const childXPathNode = xpathNode.childNodes[i] as any;
+ const childXNode = this.convertXPathNodeToXNode(childXPathNode, ownerDoc);
+ if (childXNode) {
+ childXNode.parentNode = node;
+ node.childNodes.push(childXNode);
+ }
+ }
+ if (node.childNodes.length > 0) {
+ node.firstChild = node.childNodes[0];
+ node.lastChild = node.childNodes[node.childNodes.length - 1];
+ }
+ }
+ }
+
+ return node;
+ }
+
/**
* Convert an XML node to a JSON string representation.
* This is a simplified implementation of XSLT 3.0's xml-to-json().
diff --git a/src/xslt/xslt.ts b/src/xslt/xslt.ts
index 6c6692e..325e055 100644
--- a/src/xslt/xslt.ts
+++ b/src/xslt/xslt.ts
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Copyright 2018 Johannes Wilm
// Copyright 2005 Google Inc.
// All Rights Reserved
diff --git a/tests/dom.test.tsx b/tests/dom.test.tsx
index 24c0d61..d2fab6e 100644
--- a/tests/dom.test.tsx
+++ b/tests/dom.test.tsx
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Copyright 2018 Johannes Wilm
// Copyright 2005 Google Inc.
// All Rights Reserved
diff --git a/tests/json-to-xml.test.tsx b/tests/json-to-xml.test.tsx
new file mode 100644
index 0000000..1b120de
--- /dev/null
+++ b/tests/json-to-xml.test.tsx
@@ -0,0 +1,383 @@
+/* eslint-disable no-useless-escape */
+import assert from 'assert';
+
+import { Xslt } from '../src/xslt';
+import { XmlParser } from '../src/dom';
+
+describe('json-to-xml', () => {
+ it('json-to-xml() should throw error in XSLT 1.0', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+
+ await assert.rejects(
+ async () => await xsltClass.xsltProcess(xml, xslt),
+ {
+ message: /json-to-xml\(\) is not supported in XSLT 1\.0/
+ }
+ );
+ });
+
+ it('json-to-xml() should convert simple string JSON in XSLT 3.0', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain a root element with text content "hello"
+ assert(outXmlString.includes('hello'));
+ });
+
+ it('json-to-xml() should convert simple number JSON', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain the number 42
+ assert(outXmlString.includes('42'));
+ });
+
+ it('json-to-xml() should convert boolean true', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain "true"
+ assert(outXmlString.includes('true'));
+ });
+
+ it('json-to-xml() should convert boolean false', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain "false"
+ assert(outXmlString.includes('false'));
+ });
+
+ it('json-to-xml() should convert null JSON', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain an empty root element
+ assert(outXmlString.includes(' {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain name and age elements
+ assert(outXmlString.includes('name'));
+ assert(outXmlString.includes('John'));
+ assert(outXmlString.includes('age'));
+ assert(outXmlString.includes('30'));
+ });
+
+ it('json-to-xml() should convert nested objects', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain nested person element
+ assert(outXmlString.includes('person'));
+ assert(outXmlString.includes('name'));
+ assert(outXmlString.includes('John'));
+ });
+
+ it('json-to-xml() should handle object with null value', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain value element (empty)
+ assert(outXmlString.includes('value'));
+ });
+
+ it('json-to-xml() should convert simple array', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain item elements
+ assert(outXmlString.includes('item'));
+ assert(outXmlString.includes('1'));
+ assert(outXmlString.includes('2'));
+ assert(outXmlString.includes('3'));
+ });
+
+ it('json-to-xml() should convert array of objects', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain multiple item elements with id
+ assert(outXmlString.includes('item'));
+ assert(outXmlString.includes('id'));
+ assert(outXmlString.includes('1'));
+ assert(outXmlString.includes('2'));
+ });
+
+ it('json-to-xml() should convert empty array', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain root element (empty)
+ assert(outXmlString.includes(' {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should contain items and item elements
+ assert(outXmlString.includes('items'));
+ assert(outXmlString.includes('item'));
+ assert(outXmlString.includes('1'));
+ });
+
+ it('json-to-xml() should sanitize property names starting with numbers', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Should convert property name to valid XML element (prefixed with underscore)
+ assert(outXmlString.includes('prop') || outXmlString.includes('_'));
+ });
+
+ it('json-to-xml() should handle empty and whitespace JSON strings', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+ yes
+
+
+ yes
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Empty/whitespace JSON should return empty/null result
+ assert(outXmlString.includes('notFound'));
+ });
+
+ it('json-to-xml() should handle invalid JSON gracefully', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+
+
+ yes
+
+
+ yes
+
+
+
+ `;
+
+ const xsltClass = new Xslt();
+ const xmlParser = new XmlParser();
+ const xml = xmlParser.xmlParse(xmlString);
+ const xslt = xmlParser.xmlParse(xsltString);
+ const outXmlString = await xsltClass.xsltProcess(xml, xslt);
+
+ // Invalid JSON should return null/empty result
+ assert(outXmlString.includes('notFound'));
+ });
+});
diff --git a/tests/xml/xmltoken.test.tsx b/tests/xml/xmltoken.test.tsx
index aaec736..1e4852a 100644
--- a/tests/xml/xmltoken.test.tsx
+++ b/tests/xml/xmltoken.test.tsx
@@ -1,4 +1,4 @@
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Copyright 2018 Johannes Wilm
// Copyright 2006, Google Inc.
// All Rights Reserved
diff --git a/tests/xslt/xslt-validation.test.tsx b/tests/xslt/xslt-validation.test.tsx
index 3f04219..ee7250c 100644
--- a/tests/xslt/xslt-validation.test.tsx
+++ b/tests/xslt/xslt-validation.test.tsx
@@ -1,6 +1,6 @@
/* eslint-disable no-undef */
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Tests for XSLT stylesheet/transform element validation
import assert from 'assert';
diff --git a/tests/xslt/xslt.test.tsx b/tests/xslt/xslt.test.tsx
index 9c71f8f..e98d1c3 100644
--- a/tests/xslt/xslt.test.tsx
+++ b/tests/xslt/xslt.test.tsx
@@ -1,6 +1,6 @@
/* eslint-disable no-undef */
-// Copyright 2023-2024 Design Liquido
+// Copyright 2023-2026 Design Liquido
// Copyright 2018 Johannes Wilm
// Copyright 2006, Google Inc.
// All Rights Reserved.