Search code examples
jsonxmlxsltescapingdouble-quotes

Testing nodes against literal double quote in XSLT


I've got a source XML that looks something like this:

<root>
    <item>a</item>
    <item>b</item>
    <item>"</item>
</root>

Which I am attempting to convert into a JSON object that looks roughly like this:

{"elements": [
    {"value": "a"},
    {"value": "b"},
    {"value": "\""}
]}

I've got this very nearly working with an XSLT file looking roughly like this:

<xsl:template match="root">
    <xsl:text>{"elements":[</xsl:text>
        <xsl:apply-templates select="item"/>
    <xsl:text>]}</xsl:text>
</xsl:template>

<xsl:template match="item">
    <xsl:text>{</xsl:text>
        <xsl:text>"value":"</xsl:text>
            <xsl:choose>
                <xsl:when test="current()=&quot;]">
                    <xsl:text>\"</xsl:text>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="current()"/>
                </xsl:otherwise>
            </xsl:choose>
        <xsl:text>"</xsl:text>
    <xsl:text>}</xsl:text>
    <xsl:if test="position() != last()">
        <xsl:text>,</xsl:text>
    </xsl:if>
</xsl:template>

The problem being that when I run this I get the following traceback:

Traceback (most recent call last):
  File "run_test.py", line 26, in <module>
    single_test("test.xml", "test.xslt")
  File "run_test.py", line 7, in single_test
    transform = etree.XSLT(xslt_doc)
  File "src/lxml/xslt.pxi", line 410, in lxml.etree.XSLT.__init__
lxml.etree.XSLTParseError: xsl:when : could not compile test expression 'current()="]'

Now I've tried accessing the text value of the current node in several different ways, many of which succeed in initial write, but none of which I have managed to incorporate into my test. This is what I've tried:

  • Save text in a variable, replace test with "$var=&quot;"
  • Replacing current() with text() and current()/@text
  • Replacing current with self::node()[text()=&quot;]

All of these have given me the same error, which tells me I must be misunderstanding here. Any suggestions on how to do this comparison? XSLT 1.0 preferred.


Solution

  • Literal strings in XPath expressions must be quoted. Instead of:

    <xsl:when test="current()=&quot;]">
    

    (that also has a redundant closing bracket) use:

    <xsl:when test="current()='&quot;'">
    

    or shortly:

    <xsl:when test=".='&quot;'">