XML-XSLT-转义特殊字符

时间:2018-07-06 11:00:47

标签: xml xslt saxon

这个问题与我发布的另一个问题有关,并且仍在尝试解决: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,所以我可以使用我认为是3.0的最新版本的XSLT,

谢谢!

Alexandre Jacinto

编辑

我设法像这样使用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>

例如,您可以看到<字符继续打印为&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使用的名称空间

我正确地使用了<CDATA>,但是现在,因为我有更多的<text-prop>元素,所以每个<CDATA>元素中的输出都带有<text-prop>标签,就像这样:

<?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完全一样

我知道我可能无法使用cdata-section-elements的{​​{1}}属性。

注意::在我的输入XML中,我只有一个xsl:output元素,其中包含值,其他所有元素都具有普通文本。

2 个答案:

答案 0 :(得分:0)

由于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>

答案 1 :(得分:0)

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

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

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

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

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

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

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