【问题标题】:How to parse an XML DOM inside a CDATA element in XSLT?如何在 XSLT 中解析 CDATA 元素内的 XML DOM?
【发布时间】:2012-05-06 14:10:01
【问题描述】:

假设我有一个 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 元素“名称”并将其值放在标记值中的某处。我该怎么做呢? AFAIK,我们不能对 CDATA 的内容使用 xpath。是否有一些破解/解决方法?我想在 XSLT 中严格执行此操作。

【问题讨论】:

  • CDATA 告诉 XML 解析器它不是 XML,因此它不会被解析。 它经常被滥用,因此(懒惰/不知情的)通过字符串连接创建“XML”的人不必处理正确编码的字符。如果你可以控制 XML 文件的创建,或者可以影响生成它的人,让他们停止滥用 CDATA 并将他们的 XML 内容作为 XML。

标签: xml xslt xpath cdata


【解决方案1】:

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

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

这只是一个快速的想法。如果 CDATA 中有多个名称“元素”,只需递归多次应用上述表达式即可。

【讨论】:

    【解决方案2】:

    您还可以选择 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>
    

    如果只处理 DOM,您可以应用另一个 XSL 或 XPATH。那是假设您的 CDATA 始终是有效的 XML。否则,Martin 的 RegEx 答案就是方法。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        也许我的答案来得太晚了,但我还是会给出答案。 我遇到了同样的问题,找不到易于使用的答案,所以我自己编写了一个模板“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: 再见了世界

        【讨论】:

        • 如果可能的话,我很想看看你的 str2xml 模板
        猜你喜欢
        • 2011-07-06
        • 2013-12-13
        • 1970-01-01
        • 1970-01-01
        • 2013-01-08
        • 1970-01-01
        • 1970-01-01
        • 2011-12-13
        • 2012-01-19
        相关资源
        最近更新 更多