【问题标题】:XSL unescape HTML inside CDATACDATA 中的 XSL 对 HTML 进行转义
【发布时间】:2013-12-10 08:35:04
【问题描述】:

我正在尝试转换 XML:

 <catalog>
            <country><![CDATA[ WIN8 &lt;b&gt;X&lt;/b&gt; Mac OS ]]></country>
    </catalog>

进入

<catalog>
        <country><![CDATA[  WIN8 <b>X</b> Mac OS ]]></country>        
</catalog>

使用 XSL 转换。

我知道使用 disable-output-escaping="yes" 或 cdata-section-elements 我可以将转义字符转换为未转义字符并放入 CDATA 中,但如果字符已经在 CDATA 中,这将不起作用。

有没有简单的方法呢? 谢谢。

【问题讨论】:

    标签: xml xslt cdata html-escape-characters


    【解决方案1】:

    这个

    <catalog>
      <country><![CDATA[  WIN8 <b>X</b> Mac OS ]]></country>        
    </catalog>
    

    等价于

    <catalog>
      <country> WIN8 &lt;b&gt;X&lt;/b&gt; Mac OS </country>
    </catalog>
    

    这正是你使用时得到的结果

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output omit-xml-declaration="yes" indent="yes" />
    
      <xsl:template match="node() | @*">
        <xsl:copy>
          <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="country/text()">
        <xsl:value-of select="." disable-output-escaping="yes" />
      </xsl:template>
    </xsl:stylesheet>
    

    关键是disable-output-escaping (DOE) 对落入cdata-section-elements (CSE) 的元素没有影响。那是因为这两个指令都禁用了输出转义。

    文本值" WIN8 &lt;b&gt;X&lt;/b&gt; Mac OS "变为:

    • 正常序列化时:WIN8 &amp;lt;b&amp;gt;X&amp;lt;/b&amp;gt; Mac OS

    • 使用 CSE 序列化时:&lt;![CDATA[ WIN8 &lt;b&gt;X&lt;/b&gt; Mac OS ]]&gt;

    • 使用 DOE 序列化时:WIN8 &lt;b&gt;X&lt;/b&gt; Mac OS

    注意最后两个渲染是完全相同的,除了封闭的&lt;![CDATA[ ... ]]&gt;

    CDATA 禁用元素的文本节点子节点的输出转义,作为交换将它们括在 &lt;![CDATA[ ... ]]&gt; 标记中以弥补丢失的转义级别。

    如果您在 &lt;xsl:value-of&gt; 上另外设置 DOE,该 &lt;xsl:value-of&gt; 将文本输出到已设置 CSE 的元素中,则不会发生任何事情。输出转义已被禁用。

    因此

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output omit-xml-declaration="yes" indent="yes" />
      <xsl:output cdata-section-elements="country" />
    
      <xsl:template match="node() | @*">
        <xsl:copy>
          <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="country/text()">
        <xsl:value-of select="." disable-output-escaping="yes" />
      </xsl:template>
    </xsl:stylesheet>
    

    会准确地告诉你你的输入是什么。

    这就是为什么您无法摆脱双重转义并在同一转换期间拥有CDATA 。如果您肯定必须在结果文档中包含 CDATA,则可以使用两步方法(第一步禁用输出转义,第二步添加回 CDATA)——但我个人认为这不值得。

    【讨论】:

    • 是的,我知道,但我要转换的是 CDATA 中已经转义的文本。 转换为:X Mac OS ]]> 我想保留 CDATA 并仅转换实体。我知道这不是 xml 应有的样子,但这是我的情况。
    • 忘记 CDATA。你不需要它。 CDATA 只不过是一个解析提示,与它所包含的数据无关。在 XML 文档的内存表示中,它甚至不存在。我建议您使用本机转义版本并继续处理重要的事情。
    • @andreyro 我已经添加了一些解释。
    【解决方案2】:

    这是另一种解决方案,在带有 disable-output-escaping="yes" 的 xsl:text 中使用 CDATA:

    <xsl:template match="/" >
        <xsl:text disable-output-escaping="yes"><![CDATA[
        <script>
        var thisTextIsNotEscaped = "<b>this text is normally escaped, but not in this case</b>";
        </script>
        ]]>
    </xsl:text>
    </xsl:template>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-21
      • 1970-01-01
      • 2018-02-10
      • 1970-01-01
      相关资源
      最近更新 更多