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/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/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'; 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..f95cc46 --- /dev/null +++ b/tests/xslt/issue-187.test.ts @@ -0,0 +1,43 @@ +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); + }); + + 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