PlanetXML

Sonderzeichen maskieren mit XSLT

Bei der Erzeugung von Textdateien wie CSV oder SQL kommt es öfter vor dass man den Ausgabestring in Anführungszeichen einschließen will. Dieser darf dann natürlich selber keine Anführungszeichen enthalten oder diese müssen mit einem Backslash maskiert werden. Das folgende Template ersetzt vorgegebene Zeichen an Hand einer Tabelle.

<!-- Replacement table for string-escape -->
<chr:char-table>
    <chr:char val="&quot;" rep="\&quot;" />
    <chr:char val="&apos;" rep="\&apos;" />
    <chr:char val="\"      rep="\\" />
    <chr:char val="&#9;"   rep="\t" />
    <chr:char val="&#10;"  rep="\n" />
    <chr:char val="&#13;"  rep="\r" />
    <!-- Invalid character in XML 1.0, valid in 1.1 -->
    <!-- <chr:char val="&#12;"  rep="\f" /> -->
</chr:char-table>

<!-- Replaces characters in 'string' by the corresponding entry in 'table' -->
<xsl:template name="string-escape">
    <xsl:param    name="string" />
    <xsl:param    name="table" select="document('')/xsl:stylesheet/chr:char-table" />

    <xsl:variable name="len" select="string-length($string)" />

    <xsl:if test="$len &gt; 0">
        <xsl:variable name="chr" select="substring($string, 1, 1)" />
        <xsl:variable name="rep" select="string($table/chr:char[@val = $chr]/@rep)" />
        <xsl:choose>
            <xsl:when test="string($rep) = ''">
                <xsl:value-of select="$chr" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$rep" />
            </xsl:otherwise>
        </xsl:choose>

        <!-- Divide and Conquer to avoid Stack Overflow -->
        <xsl:call-template name="string-escape">
            <xsl:with-param name="string" select="substring($string, 2, $len div 2)" />
            <xsl:with-param name="table"  select="$table" />
        </xsl:call-template>

        <xsl:call-template name="string-escape">
            <xsl:with-param name="string" select="substring($string, 2 + $len div 2, $len div 2)" />
            <xsl:with-param name="table"  select="$table" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>