【问题标题】:XML - XSLT - Escape special charactersXML - XSLT - 转义特殊字符
【发布时间】:2018-12-14 23:26:42
【问题描述】:

这个问题与我发布的另一个问题有关,但仍在试图弄清楚,在这里:XML - XSLT - Using two XML files - Additions to XML file consulting another XML file,但由于这是一个更简单的问题,我决定写一篇关于它的新帖子,让这个问题更“可读”并且对这篇文章的未来读者有用,

我有以下 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<entry>
    <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
</entry>

我只是用 XSLT 执行简单的身份转换方法:

   <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8"/>
    <xsl:strip-space elements="*"/>

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

   </xsl:stylesheet>

但我得到了输出:

<?xml version="1.0" encoding="utf-8"?>
<entry>
   <text-prop name="content">&lt;value-of&gt;new Date()&lt;/value-of&gt;</text-prop>
</entry>

但我希望输出 XML 与输入 XML 完全相同

<?xml version="1.0" encoding="UTF-8"?>
    <entry>
       <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]> </text-prop>
    </entry>

有没有一种简单的方法可以做到这一点,也许可以转义 XML 中所有可能的特殊字符?

我使用的是 Saxon 9.8,所以我可以使用最新版本的 XSLT,我认为是 3.0,

谢谢!

亚历山大·哈辛托

编辑

我设法像这样使用cdata-section-elements 转义字符:

 <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" cdata-section-elements="text-prop"/>
    <xsl:strip-space elements="*"/>

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

</xsl:stylesheet>

但是当我尝试使用不同的输入时,我在我之前引用的帖子中使用的那个:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
    <text-prop name="displayName">PersonTemplate</text-prop>
    <setup>
        <simple-master-page name="MasterPage" id="2">
            <footer>
                <text id="3">
                    <prop name="contentType">html</prop>
                    <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
                </text>
            </footer>
        </simple-master-page>
    </setup>
    <body>
        <table id="4">  
            <column id="17"/>
            <column id="18"/>
            <column id="19"/>
            <header>
                <row id="5">
                    <cell id="6">
                        <label id="20">
                            <text-prop name="text">NameTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="7">
                        <label id="21">
                            <text-prop name="text">CityTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="8">
                        <label id="22">
                            <text-prop name="text">AgeTitle</text-prop>
                        </label>
                    </cell>
                </row>
            </header>
            <detail>
                <row id="9">
                    <cell id="10"/>
                    <cell id="11"/>
                    <cell id="12"/>
                </row>
            </detail>
        </table>
    </body>
</report>

转义不起作用,所以我明白了:

<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
   <text-prop name="displayName">PersonTemplate</text-prop>
   <setup>
      <simple-master-page name="MasterPage" id="2">
         <footer>
            <text id="3">
               <prop name="contentType">html</prop>
               <text-prop name="content">&lt;value-of&gt;new Date()&lt;/value-of&gt;</text-prop>
            </text>
         </footer>
      </simple-master-page>
   </setup>
   <body>
      <table id="4">
         <column id="17"/>
         <column id="18"/>
         <column id="19"/>
         <header>
            <row id="5">
               <cell id="6">
                  <label id="20">
                     <text-prop name="text">NameTitle</text-prop>
                  </label>
               </cell>
               <cell id="7">
                  <label id="21">
                     <text-prop name="text">CityTitle</text-prop>
                  </label>
               </cell>
               <cell id="8">
                  <label id="22">
                     <text-prop name="text">AgeTitle</text-prop>
                  </label>
               </cell>
            </row>
         </header>
         <detail>
            <row id="9">
               <cell id="10"/>
               <cell id="11"/>
               <cell id="12"/>
            </row>
         </detail>
      </table>
   </body>
</report>

如您所见,&amp;lt; 字符继续打印为&amp;lt;,例如,

我只是不明白为什么它适用于第一个更简单的输入 XML,但不适用于第二个,

我该如何解决这个问题?

谢谢!

编辑

我应用了这个 XSLT 代码:

    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                              xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" cdata-section-elements="xmlbirtns:text-prop"/>
    <xsl:strip-space elements="*"/>

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

</xsl:stylesheet>

在 XSLT 文件中声明输入 XML 使用的命名空间,

我得到了&lt;CDATA&gt; 正确,但现在,因为我有更多&lt;text-prop&gt; 元素,输出在每个&lt;text-prop&gt; 元素中都带有&lt;CDATA&gt; 标签,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
   <text-prop name="displayName"><![CDATA[PersonTemplate]]></text-prop>
   <setup>
      <simple-master-page name="MasterPage" id="2">
         <footer>
            <text id="3">
               <prop name="contentType">html</prop>
               <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
            </text>
         </footer>
      </simple-master-page>
   </setup>
   <body>
      <table id="4">
         <column id="17"/>
         <column id="18"/>
         <column id="19"/>
         <header>
            <row id="5">
               <cell id="6">
                  <label id="20">
                     <text-prop name="text"><![CDATA[NameTitle]]></text-prop>
                  </label>
               </cell>
               <cell id="7">
                  <label id="21">
                     <text-prop name="text"><![CDATA[CityTitle]]></text-prop>
                  </label>
               </cell>
               <cell id="8">
                  <label id="22">
                     <text-prop name="text"><![CDATA[AgeTitle]]></text-prop>
                  </label>
               </cell>
            </row>
         </header>
         <detail>
            <row id="9">
               <cell id="10"/>
               <cell id="11"/>
               <cell id="12"/>
            </row>
         </detail>
      </table>
   </body>
</report>

按照我想要的方式获取输出 XML,这与输入 XML 完全相同

我知道我可能无法使用 xsl:outputcdata-section-elements 属性。

注意:我的输入 XML 中只有一个带有值的 &lt;text-prop&gt; 元素,所有其他元素中都有普通文本。

【问题讨论】:

  • 为什么这对您来说是个大问题?如果其他节点没有cdata的话,就一样了。您与更改的其他元素无关。我尝试了几个选项只是为了得到它,但不能。希望其他人能解决它
  • 问题是我只希望 节点之一具有 CDATA,就像在输入 XML 文件中一样。但是当我使用 cdata-section-elements 属性时,它适用于所有 标签,但我只希望它适用于 标签内的标签

标签: xml xslt saxon


【解决方案1】:

首先,CDATA 不是 XDM 数据模型的一部分,它被认为是一种纯粹的转义特殊字符的替代方式:两种形式

<X><![CDATA[<>]]></X>

<X>&lt;&gt;</X>

被认为是完全可以互换的。

这意味着您的样式表无法区分输入时使用了两者中的哪一个:无法知道。

xsl:output 上的 cdata-section-elements 属性让您可以控制在输出中使用哪种形式,但正如您所发现的,它并不能让您完全控制。

您可以通过使用禁用输出转义、字符映射或 Andrew Welch 的 lexev 实用程序来获得更多控制,但所有这些变通方法都引出了一个问题,为什么它如此重要?如果有人根据是否使用 CDATA 对结果文档进行不同的处理,那么他们就是在滥用 XML,需要重新教育。

【讨论】:

  • 我刚刚检查过,将使用我的 XML 的“系统”接受它有 ]]>&lt ;> ,所以这不再是问题了。无论如何,我解决了它,就像我在 XSLT FIDDLE 中@TimC 的评论下面显示的那样。基本上,我认为我必须像它一样通过 CDATA,但就像你说的那样,它是可互换的,“系统”接受任何一种方式。感谢您的回答和信息!
  • 现在我有一个问题,在执行 indentity 转换后,向 XML 添加新元素/标签...我在这里发布了一个与此相关的问题:stackoverflow.com/questions/51200894/… 这个问题还包括处理document() 函数,这对我来说是一个全新的东西。
【解决方案2】:

由于 XSLT 总是首先匹配最准确的模板,您可以只匹配 setup/text-prop 并专门为此部分创建一个 CDATA 块。 然后根据 XML,您可以使用 apply-templates 继续匹配其他元素。

它可能看起来像这样:

 <xsl:template match="setup/text-prop">
  <xsl:copy>
    <setup>
      <text-prop>
         <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
         <xsl:value-of>whatever</xsl:value-of>
         <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
      </text-prop>
    </setup>
   <xsl:copy>
   <xsl:apply-templates/>
  </xsl:template>

【讨论】:

  • 我试过这样(参见 XSLT FIDDLE):xsltfiddle.liberty-development.net/6qVRKwg/14。我正在尝试首先复制整个输入 XML 文件,然后在 setup/text-prop 标记中更改该值。它不起作用,因为我不太确定如何使用身份转换来复制整个输入 XML 文件,然后对其应用更改
  • 几乎是正确的,但是该行的输入是:new Date()]]> 和您提供的 XSLT prodocues: new Date()]]> ,表示缺少属性名
  • 我是这样解决的,但是不是很优雅...xsltfiddle.liberty-development.net/6qVRKwg/19
  • 嗨,不错。你也可以只匹配 text/text-prop ,现在我看到了 XML,我想你也可以使用 text-prop[@name='content'] 但我只能访问我的手机,所以不容易验证:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-21
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多