0

Input xml:

<Parent>
    <Child attr="thing">stuff</Child>
</Parent>

xslt:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="Child">
        <newChild chars="{..}" />
    </xsl:template>
</xsl:stylesheet>

Desired otuput:

<newChild chars="&lt;Child attr=&quot;thing&quot;&gt;stuff&lt;/Child&gt;" />

Note that the value of the 'chars' attribute is just the escaped version of the 'Child' tag.

Problem: how do I get the currently matched element in to the attribute? I though that .. would normally do it, but seems not to when talking about attributes, I just get some random xml entities followed by the value of the Child tag e.g. <newChild chars="&#xA; stuff&#xA;"/>. I'm expecting there might need to be some escaping stuff to make it valid.

Any suggestions appreciated.

(and before everyone asks why I'd want to do something like this, I'm constrained by the api of the application I'm connecting to)

  • AFAIK there isn't a simple or built-in way to escape an XML node tree in the output, but luckily there's a way to do it that's not too involved: http://stackoverflow.com/a/1162495/1945651 – JLRishe May 14 '13 at 15:20

2 Answers2

0

It looks like you have to build this up bit by bit. Note that .. points to Parent. You want probably want to create "&lt;Child attr=&quot;", append <value-of select='@attr'/>, "&gt;", <value-of select="."/> , "&lt;/Child>", concatenate all of them and create a chars attribute using <xsl:attribute/>

Something like:

   <newChild >
     <xsl:attribute name="chars">&lt;Child attr=&quot;<xsl:value-of select="@attr"/>"&gt;"<value-of select="."/>&lt;/Child&gt;</xsl:attribute>
   </newChild>

Haven't checked it but hope it helps.

However it is very error-prone. If I had to do this, I'd probably not use XSLT, but a DOM that has a "toXML()" method and run an escapeXML() over it.

peter.murray.rust
  • 37,407
  • 44
  • 153
  • 217
0

Here an adaption of the solution mention by JLRishe.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*" mode="asEscapedString">
        <xsl:text> </xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text disable-output-escaping="yes"><![CDATA[=&quot;]]></xsl:text>
        <xsl:value-of select="."/>
        <xsl:text disable-output-escaping="yes"><![CDATA[&quot;]]></xsl:text>
    </xsl:template>

    <xsl:template match="*" mode="asEscapedString">
        <xsl:text>&lt;</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text></xsl:text>
        <xsl:apply-templates select="@*" mode="asEscapedString"/>
        <xsl:text>&gt;</xsl:text>
        <xsl:apply-templates select="node()" mode="asEscapedString"/>
        <xsl:text>&lt;/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</xsl:text>
    </xsl:template>

    <xsl:template match="Child">
        <newChild>
            <xsl:attribute name="chars">
                <xsl:apply-templates mode="asEscapedString" select="." />
            </xsl:attribute>
        </newChild>

    </xsl:template>
    <xsl:template match="*">
        <xsl:apply-templates select="Child"/>
    </xsl:template>
</xsl:stylesheet>

This will generate the following output:

<newChild chars="&lt;Child attr=&amp;quot;thing&amp;quot;&gt;stuff&lt;/Child&gt;"/>

Attention: This far away from an general solution. This works for your simple example.

hr_117
  • 9,589
  • 1
  • 18
  • 23