Leonid Bor
Leonid Bor

Reputation: 2264

Is it possible to replace & with & in XSLT?

I tried to do that with replace($val, 'amp;', ''), but seems like & is atomic entity to the parser. Any other ideas?

I need it to get rid of double escaping, so I have constructions like ᾰ in input file.

UPD: Also one important notice: I have to make this substitution only inside of specific tags, not inside of every tag.

Upvotes: 1

Views: 8015

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167491

If you serialize there is always (if supported) the disable-output-escaping hack, see http://xsltransform.hikmatu.com/nbUY4kh which transforms

<root>
    <foo>a &amp; b</foo>
    <bar>a &amp; b</bar>
</root>

selectively into

<root>
    <foo>a & b</foo>
    <bar>a &amp; b</bar>
</root>

by using <xsl:value-of select="." disable-output-escaping="yes"/> in the template matching foo/text():

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

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

    <xsl:template match="foo/text()">
        <xsl:value-of select="." disable-output-escaping="yes"/>
    </xsl:template>
</xsl:transform>

To achieve the same selective replacement with a character map you could replace the ampersand in foo text() children (or descendants if necessary) with a character not used elsewhere in your document and then use the map to map it to an unescaped ampersand:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output use-character-maps="doe"/>

    <xsl:character-map name="doe">
        <xsl:output-character character="«" string="&amp;"/>
    </xsl:character-map>

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

    <xsl:template match="foo/text()">
        <xsl:value-of select="replace(., '&amp;', '«')"/>
    </xsl:template>

</xsl:transform>

That way

<root>
    <foo>a &amp; b</foo>
    <bar>a &amp; b</bar>
</root>

is also transformed to

<root>
    <foo>a & b</foo>
    <bar>a &amp; b</bar>
</root>

see http://xsltransform.hikmatu.com/pPgCcoj for a sample.

Upvotes: 3

Michael Kay
Michael Kay

Reputation: 163282

If your XML contains &#8112; and you believe that this is a double-escaped representation of the character with codepoint 8112, then you can convert it to this character using the XPath expression

codepoints-to-string(xs:integer(replace($input, '&#([0-9]+);', $1)))

remembering that if you write this XPath expression in XSLT, then the & must be written as &amp;.

Upvotes: 2

Related Questions