Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT + Replacing double quotes with escape sequence

Tags:

json

xml

xslt

I have the following xslt to transform data into a JQuery-accepted format. However, because JSON doesn't accept double quotes in the data string, I need to replace " with an escape sequence \"

XML:

<?xml version="1.0" encoding="UTF-8"?>
<Rowsets>
    <Rowset>
        <Columns>
            <Column Description="Element_1" SQLDataType="12" />
            <Column Description="Element_2" SQLDataType="12" />
            <Column Description="Element_3" SQLDataType="93" />
        </Columns>
        <Row>
            <Element_1>test_data</Element_1>
            <Element_2>test_quo"te</Element_2>
            <Element_3>test_data</Element_3>
        </Row>
    </Rowset>
</Rowsets>

Current XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://xml.apache.org/xslt/java" exclude-result-prefixes="java">
    <xsl:output method="text" media-type="text/csv" encoding="UTF-8"/>
    <xsl:param name="RowDelim">],</xsl:param>
    <xsl:param name="RowLast">]</xsl:param>
    <xsl:param name="RowStart">[</xsl:param>
    <xsl:param name="startBracket">{ </xsl:param>
    <xsl:param name="JQTableData">"aaData": [</xsl:param>
    <xsl:param name="JQTableEnd">] }</xsl:param>
    <xsl:param name="FieldDelim">,</xsl:param>
    <xsl:param name="StringDelim">"</xsl:param>
    <xsl:param name="DateFormat">yyyy-MM-dd HH:mm:ss</xsl:param>


    <xsl:template match="/">





        <xsl:for-each select="Rowsets">

            <xsl:for-each select="Rowset">
            <xsl:value-of select="$startBracket"/>
            <xsl:value-of select="$JQTableData"/>
                <xsl:variable name="CurrentColumns" select="Columns"/>
                <xsl:for-each select="Columns">
                    <xsl:for-each select="Column">

                        <xsl:if test="not(position() = last())">

                        </xsl:if>
                    </xsl:for-each>

                </xsl:for-each>
                <xsl:for-each select="Row">
                <xsl:value-of select="$RowStart"/>
                    <xsl:for-each select="*">
                        <xsl:variable name="ColName">
                            <xsl:value-of select="name(.)"/>
                        </xsl:variable>
                        <xsl:variable name="ColType">
                            <xsl:value-of select="$CurrentColumns/Column[@Name=$ColName]/@SQLDataType"/>
                        </xsl:variable>
                        <xsl:choose>
                            <xsl:when test="$ColType= '2' or $ColType= '3' or $ColType= '4' or $ColType= '5' or 

$ColType= '6' or $ColType= '7' or $ColType= '8' or $ColType= '-7'">
                                <xsl:value-of select="."/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="$StringDelim"/>
                                <xsl:choose>
                                    <xsl:when test="$ColType= '91' or $ColType= '92' or $ColType= '93'">
                                        <xsl:choose>
                                            <xsl:when test=". = 'TimeUnavailable'">
                                                <xsl:value-of select="."/>
                                            </xsl:when>
                                            <xsl:otherwise>
                                                                                        </xsl:otherwise>
                                        </xsl:choose>
                                    </xsl:when>
                                    <xsl:otherwise>
                                    <xsl:choose>
                                        <xsl:when test=". = 'true'">
                                            <xsl:text>Y</xsl:text>
                                        </xsl:when>
                                        <xsl:when test=". = 'false'">
                                            <xsl:text>N</xsl:text>
                                        </xsl:when>
                                        <xsl:otherwise>
                                            <xsl:value-of select="."/>
                                        </xsl:otherwise>
                                        </xsl:choose>
                                    </xsl:otherwise>
                                </xsl:choose>
                                <xsl:value-of select="$StringDelim"/>
                            </xsl:otherwise>
                        </xsl:choose>
                        <xsl:if test="not(position() = last())">
                            <xsl:value-of select="$FieldDelim"/>
                        </xsl:if>
                    </xsl:for-each>
                            <xsl:if test="not(position() = last())">
                            <xsl:value-of select="$RowDelim"/>
                        </xsl:if>
                            <xsl:if test="position() = last()">
                            <xsl:value-of select="$RowLast"/>
                        </xsl:if>

                </xsl:for-each>
                <xsl:value-of select="$JQTableEnd"/>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>



</xsl:stylesheet>

Current output:

{ "aaData": [["test_data","test_quo"te","test_data"]] }

Desired output:

{ "aaData": [["test_data","test_quo\"te","test_data"]] }
like image 491
user1130511 Avatar asked Feb 21 '12 00:02

user1130511


People also ask

How do you escape a single quote in XSLT?

You can use the built-in entities &apos; and &quot; In XSLT 1.0: Alternatively, you can define your $Q and $APOS variables (put the content (the literal " or the literal ' character) in the body of the xsl:variable , not in the select attribute).

How do I disable escaping output in XSLT?

If you code disable-output-escaping="yes" , the character > is written instead. The XSLT processor uses this attribute only if you use the html or xml output methods. If you use <xsl:output method="test"> , the attribute is ignored becasue output escaping is not done for the text output method.

How do I replace in XSLT?

XSLT replace is deterministic and does string manipulation that replaces a sequence of characters defined inside a string that matches an expression. In simple terms, it does string substitution in the specified place by replacing any substrings. Fn: replace function is not available in XSLT1.

Can we reassign a value to variable in XSLT?

Variables in XSLT are not really variables, as their values cannot be changed. They resemble constants from conventional programming languages. The only way in which a variable can be changed is by declaring it inside a for-each loop, in which case its value will be updated for every iteration.


1 Answers

Add this template to your code:

    <xsl:template name="escapeQuote">
      <xsl:param name="pText" select="."/>

      <xsl:if test="string-length($pText) >0">
       <xsl:value-of select=
        "substring-before(concat($pText, '&quot;'), '&quot;')"/>

       <xsl:if test="contains($pText, '&quot;')">
        <xsl:text>\"</xsl:text>

        <xsl:call-template name="escapeQuote">
          <xsl:with-param name="pText" select=
          "substring-after($pText, '&quot;')"/>
        </xsl:call-template>
       </xsl:if>
      </xsl:if>
    </xsl:template>

Then change:

<xsl:value-of select="."/>

to:

<xsl:call-template name="escapeQuote"/>

Your complete transformation now becomes:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:java="http://xml.apache.org/xslt/java" exclude-result-prefixes="java">
        <xsl:output method="text" media-type="text/csv" encoding="UTF-8"/>
        <xsl:param name="RowDelim">],</xsl:param>
        <xsl:param name="RowLast">]</xsl:param>
        <xsl:param name="RowStart">[</xsl:param>
        <xsl:param name="startBracket">{ </xsl:param>
        <xsl:param name="JQTableData">"aaData": [</xsl:param>
        <xsl:param name="JQTableEnd">] }</xsl:param>
        <xsl:param name="FieldDelim">,</xsl:param>
        <xsl:param name="StringDelim">"</xsl:param>
        <xsl:param name="DateFormat">yyyy-MM-dd HH:mm:ss</xsl:param>


        <xsl:template match="/">

            <xsl:for-each select="Rowsets">

                <xsl:for-each select="Rowset">
                <xsl:value-of select="$startBracket"/>
                <xsl:value-of select="$JQTableData"/>
                    <xsl:variable name="CurrentColumns" select="Columns"/>
                    <xsl:for-each select="Columns">
                        <xsl:for-each select="Column">

                            <xsl:if test="not(position() = last())">

                            </xsl:if>
                        </xsl:for-each>

                    </xsl:for-each>
                    <xsl:for-each select="Row">
                    <xsl:value-of select="$RowStart"/>
                        <xsl:for-each select="*">
                            <xsl:variable name="ColName">
                                <xsl:value-of select="name(.)"/>
                            </xsl:variable>
                            <xsl:variable name="ColType">
                                <xsl:value-of select="$CurrentColumns/Column[@Name=$ColName]/@SQLDataType"/>
                            </xsl:variable>
                            <xsl:choose>
                                <xsl:when test="$ColType= '2' or $ColType= '3' or $ColType= '4' or $ColType= '5' or

    $ColType= '6' or $ColType= '7' or $ColType= '8' or $ColType= '-7'">
                                    <xsl:value-of select="."/>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:value-of select="$StringDelim"/>
                                    <xsl:choose>
                                        <xsl:when test="$ColType= '91' or $ColType= '92' or $ColType= '93'">
                                            <xsl:choose>
                                                <xsl:when test=". = 'TimeUnavailable'">
                                                    <xsl:value-of select="."/>
                                                </xsl:when>
                                                <xsl:otherwise>
                                                                                            </xsl:otherwise>
                                            </xsl:choose>
                                        </xsl:when>
                                        <xsl:otherwise>
                                        <xsl:choose>
                                            <xsl:when test=". = 'true'">
                                                <xsl:text>Y</xsl:text>
                                            </xsl:when>
                                            <xsl:when test=". = 'false'">
                                                <xsl:text>N</xsl:text>
                                            </xsl:when>
                                            <xsl:otherwise>
                                              <xsl:call-template name="escapeQuote"/>
                                                <!-- <xsl:value-of select="."/> -->
                                            </xsl:otherwise>
                                            </xsl:choose>
                                        </xsl:otherwise>
                                    </xsl:choose>
                                    <xsl:value-of select="$StringDelim"/>
                                </xsl:otherwise>
                            </xsl:choose>
                            <xsl:if test="not(position() = last())">
                                <xsl:value-of select="$FieldDelim"/>
                            </xsl:if>
                        </xsl:for-each>
                                <xsl:if test="not(position() = last())">
                                <xsl:value-of select="$RowDelim"/>
                            </xsl:if>
                                <xsl:if test="position() = last()">
                                <xsl:value-of select="$RowLast"/>
                            </xsl:if>

                    </xsl:for-each>
                    <xsl:value-of select="$JQTableEnd"/>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:template>

        <xsl:template name="escapeQuote">
          <xsl:param name="pText" select="."/>

          <xsl:if test="string-length($pText) >0">
           <xsl:value-of select=
            "substring-before(concat($pText, '&quot;'), '&quot;')"/>

           <xsl:if test="contains($pText, '&quot;')">
            <xsl:text>\"</xsl:text>

            <xsl:call-template name="escapeQuote">
              <xsl:with-param name="pText" select=
              "substring-after($pText, '&quot;')"/>
            </xsl:call-template>
           </xsl:if>
          </xsl:if>
        </xsl:template>

</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<Rowsets>
    <Rowset>
        <Columns>
            <Column Description="Element_1" SQLDataType="12" />
            <Column Description="Element_2" SQLDataType="12" />
            <Column Description="Element_3" SQLDataType="93" />
        </Columns>
        <Row>
            <Element_1>test_data</Element_1>
            <Element_2>test_quo"te</Element_2>
            <Element_3>test_data</Element_3>
        </Row>
    </Rowset>
</Rowsets>

the wanted, correct result is produced:

{ "aaData": [["test_data","test_quo\"te","test_data"]] }
like image 96
Dimitre Novatchev Avatar answered Oct 17 '22 10:10

Dimitre Novatchev