How to unescape XML characters with help of XSLT?

2019-01-08 23:20发布

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 get it as valid formatted HTML when I place it inside of the body tag.

标签: xml xslt
4条回答
干净又极端
2楼-- · 2019-01-08 23:56

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.

查看更多
做个烂人
3楼-- · 2019-01-09 00:04

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>
查看更多
地球回转人心会变
4楼-- · 2019-01-09 00:08

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>
查看更多
时光不老,我们不散
5楼-- · 2019-01-09 00:12
<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.

查看更多
登录 后发表回答