From 354c78d4d78e3b6bbb2083df795100994c95e84d Mon Sep 17 00:00:00 2001
From: Leonel Sanches da Silva
<53848829+leonelsanchesdasilva@users.noreply.github.com>
Date: Sat, 21 Mar 2026 18:23:35 -0700
Subject: [PATCH 1/3] Exposing `xmlTransformedText ` as requested at
https://github.com/DesignLiquido/xslt-processor/issues/187.
---
src/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/index.ts b/src/index.ts
index 668b563..c76a99a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,3 @@
export { XPath, ExprContext } from './xpath';
export { Xslt, XsltOptions } from './xslt';
-export { XmlParser, xmlEscapeText, XDocument, XNode, domDocumentToXDocument } from './dom';
+export { XmlParser, xmlEscapeText, xmlTransformedText, XDocument, XNode, domDocumentToXDocument } from './dom';
From 5beb6f9b9a7abe8adced472ca627335cab5c0c0c Mon Sep 17 00:00:00 2001
From: Leonel Sanches da Silva
<53848829+leonelsanchesdasilva@users.noreply.github.com>
Date: Sat, 21 Mar 2026 18:24:12 -0700
Subject: [PATCH 2/3] Removing padding spaces to avoid problems with test
snapshots, as reported at
https://github.com/DesignLiquido/xslt-processor/issues/187.
---
src/dom/xml-functions.ts | 2 +-
tests/xml/xml.test.tsx | 16 +++++++++++++++-
tests/xslt/issue-187.test.ts | 23 +++++++++++++++++++++++
3 files changed, 39 insertions(+), 2 deletions(-)
create mode 100644 tests/xslt/issue-187.test.ts
diff --git a/src/dom/xml-functions.ts b/src/dom/xml-functions.ts
index 0197d28..7082012 100644
--- a/src/dom/xml-functions.ts
+++ b/src/dom/xml-functions.ts
@@ -244,7 +244,7 @@ function xmlTransformedTextRecursive(node: XNode, buffer: string[], options: Xml
}
} else if (nodeType == DOM_COMMENT_NODE) {
if (options.outputMethod !== 'text') {
- buffer.push(``);
+ buffer.push(``);
}
} else if (nodeType === DOM_PROCESSING_INSTRUCTION_NODE) {
if (options.outputMethod !== 'text') {
diff --git a/tests/xml/xml.test.tsx b/tests/xml/xml.test.tsx
index 8ea837c..6bbc490 100644
--- a/tests/xml/xml.test.tsx
+++ b/tests/xml/xml.test.tsx
@@ -1,6 +1,6 @@
import assert from 'assert';
-import { XmlParser, xmlText } from '../../src/dom';
+import { XmlParser, xmlText, xmlTransformedText } from '../../src/dom';
describe('General XML', () => {
it('Self-closing tags disabled', () => {
@@ -15,4 +15,18 @@ describe('General XML', () => {
});
assert.equal(outXmlString, '');
});
+
+ it('preserves comment boundaries in transformed serialization', () => {
+ const xmlString = '';
+
+ const xmlParser = new XmlParser();
+ const outXmlString = xmlTransformedText(xmlParser.xmlParse(xmlString), {
+ cData: true,
+ selfClosingTags: true,
+ escape: true,
+ outputMethod: 'xml'
+ });
+
+ assert.equal(outXmlString, xmlString);
+ });
});
diff --git a/tests/xslt/issue-187.test.ts b/tests/xslt/issue-187.test.ts
new file mode 100644
index 0000000..9972625
--- /dev/null
+++ b/tests/xslt/issue-187.test.ts
@@ -0,0 +1,23 @@
+import { Xslt, XmlParser } from '../../src/index';
+
+describe('Issue #187: Identity transformation adds spaces to comments', () => {
+ it('keeps comment content stable across repeated identity transforms', async () => {
+ const xslt = new Xslt();
+ const xmlParser = new XmlParser();
+
+ const xmlInput = '';
+ const stylesheet = xmlParser.xmlParse(`
+
+
+
+`);
+
+ const firstInputDoc = xmlParser.xmlParse(xmlInput);
+ const firstPass = await xslt.xsltProcess(firstInputDoc, stylesheet);
+ expect(firstPass).toBe(xmlInput);
+
+ const secondInputDoc = xmlParser.xmlParse(firstPass);
+ const secondPass = await xslt.xsltProcess(secondInputDoc, stylesheet);
+ expect(secondPass).toBe(firstPass);
+ });
+});
\ No newline at end of file
From c72beeec43bf19a21e2f8f7fd9d6f572667f393a Mon Sep 17 00:00:00 2001
From: Leonel Sanches da Silva
<53848829+leonelsanchesdasilva@users.noreply.github.com>
Date: Sat, 21 Mar 2026 18:52:28 -0700
Subject: [PATCH 3/3] Addressing Copilot's comments.
---
src/dom/xml-parser.ts | 10 +++++-----
tests/xslt/issue-187.test.ts | 20 ++++++++++++++++++++
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/src/dom/xml-parser.ts b/src/dom/xml-parser.ts
index 6db2e64..7a1425c 100644
--- a/src/dom/xml-parser.ts
+++ b/src/dom/xml-parser.ts
@@ -159,14 +159,14 @@ export class XmlParser {
}
if (htmlText.slice(i + 1, i + 4) === '!--') {
let endTagIndex = htmlText.slice(i + 4).indexOf('-->');
- if (endTagIndex) {
+ if (endTagIndex >= 0) {
let node = domCreateComment(xmlDocument, htmlText.slice(i + 4, i + endTagIndex + 4));
domAppendChild(parent, node);
i += endTagIndex + 6;
}
} else if (htmlText.slice(i + 1, i + 9) === '!DOCTYPE') {
let endTagIndex = htmlText.slice(i + 9).indexOf('>');
- if (endTagIndex) {
+ if (endTagIndex >= 0) {
const dtdValue = htmlText.slice(i + 9, i + endTagIndex + 9).trimStart();
// TODO: Not sure if this is a good solution.
// Trying to implement this: https://github.com/DesignLiquido/xslt-processor/issues/30
@@ -289,21 +289,21 @@ export class XmlParser {
}
if (xml.slice(i + 1, i + 4) === '!--') {
let endTagIndex = xml.slice(i + 4).indexOf('-->');
- if (endTagIndex) {
+ if (endTagIndex >= 0) {
let node = domCreateComment(xmlDocument, xml.slice(i + 4, i + endTagIndex + 4));
domAppendChild(parent, node);
i += endTagIndex + 6;
}
} else if (xml.slice(i + 1, i + 9) === '![CDATA[') {
let endTagIndex = xml.slice(i + 9).indexOf(']]>');
- if (endTagIndex) {
+ if (endTagIndex >= 0) {
let node = domCreateCDATASection(xmlDocument, xml.slice(i + 9, i + endTagIndex + 9));
domAppendChild(parent, node);
i += endTagIndex + 11;
}
} else if (xml.slice(i + 1, i + 9) === '!DOCTYPE') { // "!DOCTYPE" can be used in a XSLT template.
let endTagIndex = xml.slice(i + 9).indexOf('>');
- if (endTagIndex) {
+ if (endTagIndex >= 0) {
const dtdValue = xml.slice(i + 9, i + endTagIndex + 9).trimStart();
// TODO: Not sure if this is a good solution.
// Trying to implement this: https://github.com/DesignLiquido/xslt-processor/issues/30
diff --git a/tests/xslt/issue-187.test.ts b/tests/xslt/issue-187.test.ts
index 9972625..f95cc46 100644
--- a/tests/xslt/issue-187.test.ts
+++ b/tests/xslt/issue-187.test.ts
@@ -20,4 +20,24 @@ describe('Issue #187: Identity transformation adds spaces to comments', () => {
const secondPass = await xslt.xsltProcess(secondInputDoc, stylesheet);
expect(secondPass).toBe(firstPass);
});
+
+ it('keeps empty comments stable across repeated identity transforms', async () => {
+ const xslt = new Xslt();
+ const xmlParser = new XmlParser();
+
+ const xmlInput = '';
+ const stylesheet = xmlParser.xmlParse(`
+
+
+
+`);
+
+ const firstInputDoc = xmlParser.xmlParse(xmlInput);
+ const firstPass = await xslt.xsltProcess(firstInputDoc, stylesheet);
+ expect(firstPass).toBe(xmlInput);
+
+ const secondInputDoc = xmlParser.xmlParse(firstPass);
+ const secondPass = await xslt.xsltProcess(secondInputDoc, stylesheet);
+ expect(secondPass).toBe(firstPass);
+ });
});
\ No newline at end of file