如何在XSLT中解析CDATA元素中的XML DOM?

时间:2012-04-25 20:34:35

标签: xml xslt xpath cdata

说我有一个XML文件,如:

<library>
 <books>
  <![CDATA[<genre><name>Sci-fi</name><count>2</count></genre>]]>
  <book>
   <name>
    Some Book
   </name>
   <author>
    Some author
   </author>
  <book>
  <book>
   <name>
    Another Book
   </name>
   <author>
    Another author
   </author>
  <book>
 <books>
</library>

我想在xslt转换器中读取CDATA元素'name',并将其值放在标签的vaue中。我该怎么做呢? AFAIK,我们不能在CDATA的内容上使用xpath。这有什么黑客/解决方法吗?我想在XSLT中严格执行此操作。

4 个答案:

答案 0 :(得分:6)

某些XSLT产品具有扩展功能,例如saxon:parse(),它允许您获取包含词法XML的字符串并将其转换为节点树。

答案 1 :(得分:4)

您还可以选择CDATA部分,然后将结果传递给第二个XSL。

例如,如果您按照以下方式获得CDATA部分:

<xsl:template match="//books/text()">
  <xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:template>

你最终会得到如下结果:

<genre><name>Sci-fi</name><count>2</count></genre>

然后你可以应用另一个XSL,或XPATH如果只处理一个DOM。假设您的CDATA始终是有效的XML。否则,马丁的RegEx答案就是这样。

答案 2 :(得分:3)

由于CDATA块是(部分)文本节点,因此您可以在两个“标记”之间提取文本,例如像这样:

<xsl:template match="text()">
  <xsl:value-of select="substring-before(substring-after(., '&lt;name>'), '&lt;/name>')"/>
</xsl:template>

这只是一个简单的想法。如果CDATA中有多个名称“element”,则只需递归地多次应用上述表达式。

答案 3 :(得分:1)

也许我的回答太晚了,但无论如何我都会给它。 我遇到了同样的问题,找不到一个易于使用的答案,所以我自己写了一个模板“STR2XML”来做这件事。如果有人有兴趣,我很乐意分享模板。请告诉我。

两个如何运作的例子:

<xsl:variable name="text">
    <![CDATA[
        <div style="color:red;">
            <p>hello world</p>
        </div>
    ]]>
</xsl:variable>
<p>
    <xsl:value-of select="$text"/>
</p>
<xsl:call-template name="str2xml">
    <xsl:with-param name="text" select="$text"/>
</xsl:call-template>

将提供以下输出:

<div style="font-weight:bold;"> <p>hello world</p> </div> (non parsed plain text)

你好世界

但是当然你也可以使用它来创建一个可以作为节点访问的变量:

<xsl:variable name="text2">
    <![CDATA[
        <div>hello world</div>
        <p>goodbye world</p>
    ]]>
</xsl:variable>
<xsl:variable name="var1">
    <xsl:call-template name="str2xml">
        <xsl:with-param name="text" select="$text2"/>
    </xsl:call-template>
</xsl:variable>
<xsl:for-each select="xalan:nodeset($var1)/*">
    <p>
        <xsl:value-of select="concat(name(.),': ',.)"/>
    </p>
</xsl:for-each>

输出:

div:你好世界

p:再见世界