Stefan
Stefan

Reputation: 974

Using xml-to-json. "Inner XML/XHTML" should go in a json string value field

I'm using Saxon Home Edition to convert XML to JSON:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="UTF-8" />
    <xsl:template match="/">
        <xsl:variable name="xmljson">
            <map xmlns="http://www.w3.org/2005/xpath-functions">
                <string key="name">Some name</string>
                <string key="description">A nice description</string>
            </map>
        </xsl:variable>
        <xsl:value-of select="xml-to-json($xmljson)" />
    </xsl:template>
</xsl:stylesheet>

Produces the desired output:

{"name":"Some name","description":"A nice description"}

The description field contains arbitrary complex xhtml. The template rule does not work with the following description field:

<string key="description">A <strong>nice</strong> description</string>

Error message:

xml-to-json: unknown element <strong>

Enclosing the description in a CDATA section does work:

<string key="description"><![CDATA[A <strong>nice</strong> description]]></string>

Desired output:

{"name":"Some name","description":"A <strong>nice<\/strong> description"}

Problem/Question

The content of the description field is the result of a transformation. So with and withou CDATA fails. This will not work:

<string key="description"><xsl:apply-template select="description" /></string>

Neither this:

<string key="description"><![CDATA[<xsl:apply-template select="description" />]]></string>

Upvotes: 1

Views: 399

Answers (2)

Stefan
Stefan

Reputation: 974

I came up with the following quick hack. Have to check this tomorrow again, kind of tired now...t


Edit: This is a horrible hack! The template rule does not treat special characters. Please read the comments below.


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="UTF-8" />

    <xsl:template match="/">
        <xsl:variable name="doc">
            <description>A <strong class="red">nice</strong> description</description>
        </xsl:variable>
        <xsl:variable name="xmljson">
            <map xmlns="http://www.w3.org/2005/xpath-functions">
                <string key="description"><xsl:apply-templates select="$doc/description/text()|$doc/description/*" /></string>
            </map>
        </xsl:variable>
        <xsl:value-of select="xml-to-json($xmljson)" />
    </xsl:template>

    <xsl:template match="*">
        <!-- opening tag -->
        <xsl:text>&lt;</xsl:text>
        <xsl:value-of select="name()"/>
        <!-- attribute nodes -->
        <xsl:apply-templates select="@*"/>
        <xsl:text>&gt;</xsl:text>
        <xsl:apply-templates/>
        <!-- closing tag -->
        <xsl:text>&lt;</xsl:text>
        <xsl:text>/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:text> </xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>="</xsl:text>
        <xsl:value-of select="." />
        <xsl:text>"</xsl:text>
    </xsl:template>

</xsl:stylesheet>

Produces the desired output:

{"description":"A <strong class=\"red\">nice<\/strong> description"}

Upvotes: 0

Mads Hansen
Mads Hansen

Reputation: 66783

Use the serialize() function to produce escaped XML markup as text.

<xsl:variable name="options" as="element()">
  <output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
    <output:omit-xml-declaration value="yes"/>
  </output:serialization-parameters>
</xsl:variable>

<xsl:variable name="xmljson" as="element()">
  <map xmlns="http://www.w3.org/2005/xpath-functions">
    <string key="name">Some name</string>
    <string key="description"><xsl:value-of select="serialize(description, $options)"/></string>
  </map>
</xsl:variable>

Upvotes: 1

Related Questions