开发者

How to unescape XML characters with help of XSLT?

I need to unescape XML characters from inside of XML nodes with the help of only XSLT transformations. I have <text>&lt;&gt;and other possible characters</text> and need to g开发者_StackOverflowet it as valid formatted HTML when I place it inside of the body tag.


<xsl:template match="text">
  <body>
    <xsl:value-of select="." disable-output-escaping="yes" />
  </body>
</xsl:template>

Note that the output is not guaranteed to be well-formed XML anymore.


With xslt 2.0 I have come up with this one. Note that the output is not guaranteed to be correct xml, a simple unequality can mess up your output.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<xsl:character-map name="a">
    <xsl:output-character character="&lt;" string="&lt;"/>
    <xsl:output-character character="&gt;" string="&gt;"/>
</xsl:character-map>

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

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

</xsl:stylesheet>


I haven't found an answer to this question. So I came to the conclusion that this is no way to do this. I found workaround for this problem, unescaping file on server side.


Another solution. This one does not use the xml postprocessor, so readily useable as input of further xslt processing. Also guaranteed to create valid xml. This is a xslt 2.0 solution, escaping text within "documentation" tags, tested with saxon. You should modify the "allowedtags" variable to define your own data model. The immediate children are the tags, the ones below them are the attributes possible. Reading the allowed tags from an xsd is left as an excercise for the reader (please share it with me).

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fn="http://www.w3.org/2005/xpath-functions"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:my="http://magwas.rulez.org/my"
>
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:variable name="allowedtags">
<li/>
<ul/>
<br/>
<a><href/></a>
</xsl:variable>

<xsl:template match="@*|*|processing-instruction()|comment()" mode="unescape">
    <xsl:copy>
        <xsl:apply-templates select="*|@*|text()|processing-instruction()|comment()" mode="unescape"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="documentation" mode="unescape">
    <documentation>
    <xsl:call-template name="doc">
        <xsl:with-param name="str">
            <xsl:value-of select="."/>
        </xsl:with-param>
    </xsl:call-template>
    </documentation>
</xsl:template>

<xsl:template name="doc">
    <xsl:param name="str"/>
    <xsl:variable name="start" select="fn:substring-before($str,'&lt;')"/>
    <xsl:variable name="rest" select="fn:substring-after($str,'&lt;')"/>
    <xsl:variable name="fulltag" select="fn:substring-before($rest,'&gt;')"/>
    <xsl:variable name="tagparts" select="fn:tokenize($fulltag,'[  &#xA;]')"/>
    <xsl:variable name="tag" select="$tagparts[1]"/>
    <xsl:variable name="aftertag" select="fn:substring-after($rest,'&gt;')"/>
    <xsl:variable name="intag" select="fn:substring-before($aftertag,fn:concat(fn:concat('&lt;/',$tag),'&gt;'))"/>
    <xsl:variable name="afterall" select="fn:substring-after($aftertag,fn:concat(fn:concat('&lt;/',$tag),'&gt;'))"/>
    <xsl:value-of select="$start"/>
    <xsl:choose>
    <xsl:when test="$tag">
        <xsl:variable name="currtag" select="$allowedtags/*[$tag = local-name()]"/>
        <xsl:if test="$currtag">
            <xsl:element name="{$currtag/local-name()}">
                <xsl:for-each select="$tagparts[position()>1]">
                    <xsl:variable name="anstring" select="fn:replace(.,'^([^ &#xA;=]*)=.*$','$1')"/>
                    <xsl:variable name="antag" select="$currtag/*[$anstring = local-name()]"/>
                    <xsl:if test="$antag">
                        <xsl:attribute name="{$antag/local-name()}">
                            <xsl:value-of select="fn:replace(.,'^.*[^ &#34;]*&#34;([^&#34;]*)&#34;.*','$1')"/>
                        </xsl:attribute>
                    </xsl:if>
                </xsl:for-each>
                <xsl:if test="$intag">
                    <xsl:call-template name="doc">
                        <xsl:with-param name="str">
                            <xsl:value-of select="$intag"/>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:if>
            </xsl:element>
        </xsl:if>
        <xsl:if test="$afterall">
            <xsl:call-template name="doc">
                <xsl:with-param name="str">
                    <xsl:value-of select="$afterall"/>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:if>
    </xsl:when>
    <xsl:otherwise>
                    <xsl:value-of select="$str"/>
    </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜