DesignLiquido / xslt-processor

A JavaScript XSLT processor without native library dependencies
GNU Lesser General Public License v3.0
102 stars 32 forks source link

`xsl:apply-templates` for nodes inside text causes the text to print in wrong order #108

Open jrutila opened 2 days ago

jrutila commented 2 days ago

The buggy case is presented in this unit test code.

Basically, the <xsl:apply-templates> works but results in following output

<div><h2>test1</h2><p> hello<span>replaced text</span></p></div>

So the beginning of the text ("This is") is lost somewhere, the "hello" comes first and then the, correctly templated, "replaced text". If you remove the " hello" from the end, it works correctly.

    it('XSLT apply-template inside text test', async () => {
        const xmlString = `<root>
          <test name="test1">This is <repl>text</repl> hello</test>
        </root>`;

        const xsltString = `<?xml version="1.0"?>
          <xsl:stylesheet version="1.0">
            <xsl:template match="repl">
              <span>replaced <xsl:value-of select="." /></span>
            </xsl:template>
            <xsl:template match="/">
              <div>
                <h2><xsl:value-of select="test/@name" /></h2>
                <p><xsl:apply-templates select="test/node()" /></p>
              </div>
            </xsl:template>
          </xsl:stylesheet>`;

        const expectedOutString = `<div><h2>test1</h2><p>This is <span>replaced text</span> hello</p></div>`;

        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, expectedOutString);
    });
leonelsanchesdasilva commented 2 days ago

@jrutila Thanks for reporting. I implemented your unit test.

I tested your example in an online XSLT transformer and my results were a bit different:

<div>
   <h2/>
   <p/>
</div>

XML Input:

<root>
    <test name="test1">This is <repl>text</repl> hello</test>
</root>

XSLT Input:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="repl">
    <span>replaced <xsl:value-of select="." /></span>
  </xsl:template>
  <xsl:template match="/">
    <div>
      <h2><xsl:value-of select="test/@name" /></h2>
      <p><xsl:apply-templates select="test/node()" /></p>
    </div>
  </xsl:template>
</xsl:stylesheet>
jrutila commented 2 days ago

Hmm.. true. I think I tested this before but you are right. Following xslt works, though. I had to add match="/root" for some reason.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="repl">
    <span>replaced <xsl:value-of select="." /></span>
  </xsl:template>
  <xsl:template match="/root">
              <div>
                  <h2><xsl:value-of select="test/@name" /></h2>
                  <p><xsl:apply-templates select="test/node()" /></p>
              </div>
  </xsl:template>
</xsl:stylesheet>