From 42c9b3eba3dcf918e7098f1d9532674e2e9efae8 Mon Sep 17 00:00:00 2001
From: Leonel Sanches da Silva
<53848829+leonelsanchesdasilva@users.noreply.github.com>
Date: Tue, 10 Feb 2026 15:45:25 -0800
Subject: [PATCH] In HTML output mode, skipping namespace declarations (xmlns
and xmlns:*) (Resolves
https://github.com/DesignLiquido/xslt-processor/issues/165).
---
src/dom/xml-functions.ts | 6 ++++
src/xslt/xslt.ts | 6 ++++
tests/xslt/message-number-namespace.test.ts | 40 +++++++++++++++++++++
3 files changed, 52 insertions(+)
diff --git a/src/dom/xml-functions.ts b/src/dom/xml-functions.ts
index 6854082..3ec6190 100644
--- a/src/dom/xml-functions.ts
+++ b/src/dom/xml-functions.ts
@@ -317,6 +317,12 @@ function xmlElementLogicTrivial(node: XNode, buffer: string[], options: XmlOutpu
continue;
}
+ // In HTML output mode, skip namespace declarations (xmlns and xmlns:*)
+ if (options.outputMethod === 'html' &&
+ (attribute.nodeName === 'xmlns' || attribute.nodeName.startsWith('xmlns:'))) {
+ continue;
+ }
+
if (attribute.nodeName && attribute.nodeValue !== null && attribute.nodeValue !== undefined) {
buffer.push(` ${xmlFullNodeName(attribute)}="${xmlEscapeAttr(attribute.nodeValue)}"`);
}
diff --git a/src/xslt/xslt.ts b/src/xslt/xslt.ts
index 96a755e..bfa017c 100644
--- a/src/xslt/xslt.ts
+++ b/src/xslt/xslt.ts
@@ -4979,6 +4979,12 @@ export class Xslt {
} else if (namespaceUri) {
domSetAttribute(newNode, `xmlns:${aliasPrefix}`, namespaceUri);
}
+ } else if (namespaceUri) {
+ const prefix = templatePrefix || (qualifiedName.includes(':') ? qualifiedName.split(':')[0] : null);
+ const nsAttr = prefix ? `xmlns:${prefix}` : 'xmlns';
+ if (!this.isNamespaceDeclaredOnAncestor(output, nsAttr, namespaceUri)) {
+ domSetAttribute(newNode, nsAttr, namespaceUri);
+ }
}
// Apply attribute sets from use-attribute-sets attribute on literal elements
diff --git a/tests/xslt/message-number-namespace.test.ts b/tests/xslt/message-number-namespace.test.ts
index e779408..ccabdce 100644
--- a/tests/xslt/message-number-namespace.test.ts
+++ b/tests/xslt/message-number-namespace.test.ts
@@ -694,6 +694,46 @@ describe('Error messages for misplaced elements', () => {
});
});
+describe('Namespace declarations on literal result elements (issue #165)', () => {
+ it('Namespace-prefixed literal result element includes xmlns declaration', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+ Out
+
+`;
+
+ 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);
+ assert.equal(outXmlString, 'Out');
+ });
+
+ it('Nested namespace-prefixed elements do not duplicate xmlns declaration', async () => {
+ const xmlString = ``;
+
+ const xsltString = `
+
+
+ Text
+
+`;
+
+ 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);
+ assert.equal(outXmlString, 'Text');
+ });
+});
+
describe('Modes and Multiple Template Sets', () => {
it('Template in non-default mode not selected if no mode specified', async () => {
const xmlString = `