首页 文章

XML和XSLT保留CDATA

提问于
浏览
2

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

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

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

我尝试了许多解决方案,如disable-output-escaping和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

2 回答

  • 5

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

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

    Here is a short example how this is done

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

    When this transformation is applied on the following XML document:

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

    the wanted, correct result is produced

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

    In case the set of element names aren't known in advance, one can use a stylesheet that produces another stylesheet, that should be finally applied to the XML document to produce the wanted result

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

    When this transformation is applied on the same XML document (above), the result is another XSLT stylesheet

    <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方法进行分组) .

    When we finally apply the so produced XSLT stylesheet on the same XML document, we get the wanted result

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

    Explanation

    • Dynamically producing a new transformation ,使用XSLT指令 xsl:namespace-alias .

    • Muenchian grouping 确定所有不同的元素名称 .

  • 0

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

    <xsl:output omit-xml-declaration="yes"
                indent="yes"
                cdata-section-elements="Name CompanyName Text"
    />
    

相关问题