diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bd170c9..8e0142d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,10 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2-beta + - uses: actions/checkout@v4 with: - node-version: '20' + submodules: recursive + - uses: actions/setup-node@v4 + with: + node-version: '22' - uses: ArtiomTr/jest-coverage-report-action@v2 id: coverage with: diff --git a/README.md b/README.md index df3acf0..49956b2 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,54 @@ HTML per se is not strict XML. Because of that, starting on version 2.0.0, this - Tags like `
+ preserved ++
+ also preserved
+
+'));
+ });
+
+ it('xml:space="preserve" takes precedence over strip-space', async () => {
+ const xmlString = `
+
+ -
+ whitespace here
+
+ `;
+
+ 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);
+
+ // Whitespace inside item should be preserved due to xml:space="preserve"
+ assert.ok(outXmlString.includes('whitespace here'));
+ });
+
+ it('No strip-space by default - whitespace text nodes are processed', async () => {
+ // This test verifies that without strip-space, whitespace-only text nodes
+ // from the input are processed. With apply-templates, text nodes create
+ // output (though serialization may normalize whitespace for display).
+ const xmlString = `
+text `;
+
+ 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);
+
+ // Without strip-space, content should be preserved
+ assert.equal(outXmlString, `text `);
+ });
+
+ it('Strip-space applies to apply-templates', async () => {
+ const xmlString = `
+
+
+ First Book
+
+
+ Second Book
+
+ `;
+
+ 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);
+
+ assert.equal(outXmlString, `- First Book
- Second Book
`);
+ });
+
+ it('Non-whitespace text is never stripped', async () => {
+ const xmlString = `
+- actual text content
`;
+
+ 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);
+
+ // Text content should never be stripped
+ assert.equal(outXmlString, `- actual text content
`);
+ });
+});
+
+describe('xsl:preserve-space', () => {
+ it('Preserve-space keeps whitespace in specified elements', async () => {
+ const xmlString = `
+
+
+ function hello() {
+ return "world";
+ }
+
+ `;
+
+ 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);
+
+ // Code content formatting should be preserved
+ assert.ok(outXmlString.includes('function hello()'));
+ assert.ok(outXmlString.includes('return "world"'));
+ });
+});