如何在 XSLT 的帮助下对 XML 字符进行转义?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2463155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 13:01:54  来源:igfitidea点击:

How to unescape XML characters with help of XSLT?

xmlxslt

提问by Artic

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.

我需要仅在 XSLT 转换的帮助下从 XML 节点内部转义 XML 字符。<text>&lt;&gt;and other possible characters</text>当我将它放在 body 标签中时,我已经并且需要将它作为有效的格式化 HTML 获取。

回答by Tomalak

<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.

请注意,不再保证输出是格式良好的 XML。

回答by árpád Magosányi

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.

使用 xslt 2.0 我想出了这个。请注意,不能保证输出是正确的 xml,一个简单的不等式可能会弄乱您的输出。

<?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>

回答by Artic

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.

我还没有找到这个问题的答案。所以我得出的结论是,这没有办法做到这一点。我找到了解决此问题的方法,在服务器端取消转义文件。

回答by árpád Magosányi

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 后处理器,因此很容易用作进一步 xslt 处理的输入。还保证创建有效的 xml。这是一个 xslt 2.0 解决方案,转义“文档”标签中的文本,用 saxon 测试。您应该修改“allowedtags”变量以定义您自己的数据模型。直接子元素是标签,它们下面的元素是可能的属性。从 xsd 读取允许的标签留给读者作为练习(请与我分享)。

<?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;=]*)=.*$','')"/>
                    <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;.*','')"/>
                        </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>