如何使用xsl从xml节点获取CDATA?

时间:2010-06-03 06:02:59

标签: xml xslt cdata

我正在尝试使用XSL获取XML节点的CDATA内容。该 节点目前看起来像这样:

<node id="1" text="Book Information" ><![CDATA[This is sample text]]></node>

我需要This is sample text件。有没有人对此有任何想法?

提前致谢。

5 个答案:

答案 0 :(得分:10)

好吧,如果我使用这个样式表:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:template match="node/text()">
    <xsl:copy/>
  </xsl:template>
</xsl:stylesheet>

在这个XML文件上:

<?xml version="1.0" encoding="utf-8"?>
<node id=1 text="Book Information" ><![CDATA[This is sample text]]></node>

我得到一个解析错误,因为id=1是无效的XML。

在属性值(id="1")周围加上引号并重新运行样式表,我得到输出:

  

这是示例文本

所以有一个开始。基本上,只需将CDATA视为文本节点,即可开始使用。

你说:

  

我找到了类似的东西:
  <xsl:output cdata-section-elements="text"/>
  然后获取CDATA:
  <xsl:value-of select="node" />

如果你也使用value-of,这种方法也可以。以下是评论中的示例,使用value-of代替。但请注意,cdata-section-elements仅适用于输出端,指示要将哪些输出 XML元素打印为CDATA部分而不是普通的旧字符数据。它与获取数据没有任何关系。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output cdata-section-elements="foo"/>
  <xsl:template match="/">
    <foo>
      <xsl:value-of select="node"/>
    </foo>
  </xsl:template>
</xsl:stylesheet>

打印出来

<?xml version="1.0"?>
<foo><![CDATA[This is sample text]]></foo>

答案 1 :(得分:1)

实现这一目标的其他一些简单步骤;
使用W3cschools编辑器试用。
XML文件示例:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<catalog>
    <cd>
        <disk id="title"><![CDATA[Sample xml]]></disk >
        <disk id="artist"><![CDATA[Vijay]]></disk >
    </cd>
</catalog>


示例XSL文件:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
    <h2>My CD Collection</h2>
    <table border="1">
      <tr bgcolor="#9acd32">
        <th>Title</th>
        <th>Artist</th>
      </tr>
<xsl:for-each select="catalog/cd">

      <tr>
       <td><xsl:value-of select="/catalog/cd/disk[@id='title']"/></td>
       <td><xsl:value-of select="/catalog/cd/disk[@id='artist']"/></td>
       </tr>
</xsl:for-each>
    </table>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>


最终结果是;
alt text

答案 2 :(得分:0)

输出CDATA部分:

您必须使用xsl:output/@cdata-section-elements。来自http://www.w3.org/TR/xslt#output

  

cdata-section-elements属性   包含以空格分隔的列表   QNames每个QName都扩展为   使用命名空间的扩展名   有效的声明   xsl:QName中的输出元素   发生;如果有默认值   命名空间,它用于QNames   没有前缀。扩张是   在合并之前执行   多个xsl:输出元素成一个   单个有效的xsl:output元素。   如果是父的扩展名   文本节点是列表的成员,   那么文本节点应该输出为   CDATA部分。

除了DOE之外,当然。

您无法使用XPath选择CDATA部分。根据{{​​3}}

  

有七种类型的节点:

     
      
  • 根节点

  •   
  • 元素节点

  •   
  • 文本节点

  •   
  • 属性节点

  •   
  • 命名空间节点

  •   
  • 处理指令节点

  •   
  • 评论节点

  •   

来自http://www.w3.org/TR/xpath/#data-model

  

CDATA部分中的每个字符   被视为字符数据。从而,   源文档中的<![CDATA[<]]>   将被视为&lt;。都   将导致单个&lt;中的人物   树中的文本节点。因此,一个CDATA   部分被视为<![CDATA[   并且]]>被删除了   <&的出现被替换为   <{1}}和&lt;

答案 3 :(得分:0)

我在网络上找到的唯一解决方案是 -

{XSLT}    
<title>
    <xsl:text disable-output-escaping="yes"><![CDATA[ <![CDATA[  ]]></xsl:text>
    <xsl:value-of select="label" disable-output-escaping="yes"/>
    <xsl:text disable-output-escaping="yes"><![CDATA[]]]]><![CDATA[>]]></xsl:text>
</title>

但是,这不是最干净的解决方案,特别是如果您需要在XSLT的各个部分实现它。此外,如果您的输入XML已经具有CDATA(即您试图保留CDATA),则使用disable-output-escaping将无法工作,因为到那时CDATA已经被XSLT引擎解析,所有这些都将留下是最终会打破xml的内容。

这是我的解决方案 -

根据您使用XSLT的方式,可以使用外部/注入功能。这样做可以轻松地减少您正在编写的代码量,最终得到一个更清晰的模板:

{C#}
public string CDATAWrap(string data)
{
    return "<![CDATA[" + data + "]]>";
}

{XSLT}     
<title>
    <xsl:value-of select="CDataType:CDATAWrap(label)" disable-output-escaping="yes" />
</title>

答案 4 :(得分:-1)

我尝试了各种组合,并为此得到了解决方案;

 <xsl:value-of select="/node/."/>