3

我正在开发一个项目,其中包括在 xml 上应用一些 xslt。

我的输入 xml 在任何 xml 节点中都包含“CDATA”。

现在我想要的是它应该保留“CDATA”,如果它有输入

我尝试了许多解决方案,例如禁用输出转义和 cdata-section-elements 等……但我发现它们都不适合我的要求。

那么,有什么办法可以做到吗??如果输入 xml 节点有 cdata,那么它应该在输出中给出它,如果输入 xml 节点没有 cdata,那么它不应该在输出中给出它。

我有一个名为的节点,其中包含 cdata,另一个节点位于某个不包含 cdata 的差异位置。

<Address>
<Location>
<Code>912</Code>
<Value>10301</Value>
</Location>
<Name><![CDATA[E&S]]></Name>
<CompanyName><![CDATA[E&S]]></CompanyName>
<AddressLine3>dummy address</AddressLine3>
<City>dummy city</City>
<State>dummy state</State>
<PostalCode>dummy postal code</PostalCode>
<Country>dummy country</Country>
</Address>
<Nodes>
<Node>
<Type>CTU</Type>
<Text><![CDATA[dummy text & dummy Text.]]></Text>
</Node>
</Nodes>

只有预定义的节点才会包含 cdata 并不固定,它可以来自任何地方

4

2 回答 2

7

XSLT 使用的 XPath 数据模型不允许区分任何 CDATA 部分——其中任何部分都被表示为文本节点的(部分)。因此,CDATA 保存不能完全使用 XSLT 或 XPath 来实现。它可以通过基于 DOM 的方法来实现。

如果在转换的输出中,具有特定名称的元素的文本节点需要 CDATA 部分,而其他元素则不需要,那么这可以在 XSLT 中完成,在声明中指定一个cdata-section-elements属性。<xsl:output>

这是一个简短的例子

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"
 cdata-section-elements="a b c d e"/>
 <xsl:strip-space elements="*"/>

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

当此转换应用于以下 XML 文档时:

<Record>
    <a>10:30</a>
    <b>20:30</b>
    <c>10:60</c>
    <d>1:15</d>
    <e>1:03</e>
</Record>

产生了想要的正确结果

<Record>
   <a><![CDATA[10:30]]></a>
   <b><![CDATA[20:30]]></b>
   <c><![CDATA[10:60]]></c>
   <d><![CDATA[1:15]]></d>
   <e><![CDATA[1:03]]></e>
</Record>

如果事先不知道一组元素名称,可以使用生成另一个样式表的样式表,该样式表应最终应用于 XML 文档以产生所需的结果

<xsl:stylesheet version="1.0" xmlns:x="http://www.w3.org/1999/XSL/Transform"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xxx="xxx">
 <xsl:namespace-alias stylesheet-prefix="xxx" result-prefix="xsl"/>
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kElemByName" match="*[text()[normalize-space()]]" use="name()"/>

 <xsl:variable name="vDistinctNamedElems" select=
 "//*[generate-id()=generate-id(key('kElemByName',name())[1])]"/>

 <xsl:variable name="vDistinctNames">
  <xsl:for-each select="$vDistinctNamedElems">
   <xsl:value-of select="concat(name(), ' ')"/>
  </xsl:for-each>
 </xsl:variable>

 <xsl:template match="node()|@*">
  <xxx:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xxx:output omit-xml-declaration="yes" indent="yes"
       cdata-section-elements="{$vDistinctNames}"/>
    <xxx:strip-space elements="*"/>

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

当此转换应用于同一个 XML 文档(上图)时,结果是另一个 XSLT 样式表

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:x="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
   <xsl:output omit-xml-declaration="yes" indent="yes" cdata-section-elements="a b c d e "/>
   <xsl:strip-space elements="*"/>
   <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

在此样式表中,cdata-section-elements属性中的所有元素名称都是动态生成的(使用 Muenchian 方法进行分组)。

当我们最终在同一个 XML 文档上应用如此生成的 XSLT 样式表时,我们得到了想要的结果

<Record>
   <a><![CDATA[10:30]]></a>
   <b><![CDATA[20:30]]></b>
   <c><![CDATA[10:60]]></c>
   <d><![CDATA[1:15]]></d>
   <e><![CDATA[1:03]]></e>
</Record>

说明

  1. 使用 XSLT 指令动态生成新的转换xsl:namespace-alias

  2. Muenchian 分组以确定所有不同的元素名称。

于 2013-03-29T04:43:48.293 回答
0

您的解决方案是引入包含cdatasectioncdata-section-elements属性 ( uh) 中的节点/元素的名称:

<xsl:output omit-xml-declaration="yes"
            indent="yes"
            cdata-section-elements="Name CompanyName Text"
/>
于 2014-07-22T12:04:43.280 回答