【问题标题】:CDATA in XML and missing values XSLTXML 中的 CDATA 和缺失值 XSLT
【发布时间】:2016-04-08 15:58:07
【问题描述】:

我无法让国家/地区值显示在我的 XSLT 转换中,并且不确定如何处理我的 XSLT 中的 CDATA 标记

这是我的 XML:

<catalog xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org">
<cd>
    <title>Empire Burlesque</title>
    <description><![CDATA[
      <div>
        <b>Country:</b>
        <a href="location.html">Canada</a>
        <b>City:</b>
        <a href="location.html">Calgary</a>
      </div>            
    ]]></description>
</cd>
<cd>
    <title>Hide your heart</title>
    <description><![CDATA[
      <div>
        <b>Country:</b>
        <a href="location.html">Canada</a>
        <b>City:</b>
        <a href="location.html">Toronto</a>
      </div>    
    ]]></description>
</cd>
</catalog>

这是我的 XSLT:

<xsl:template match="/">
    <xsl:for-each select="catalog/cd">
        <p>Title: <xsl:value-of select="title"/></p> 
        <p>Country: <xsl:value-of select="description/div/b['Country:']/following-sibling::a" disable-output-escaping="yes"/></p>
   </xsl:for-each>
</xsl:template>

我的结果是:

<p>Title: Empire Burlesque</p>
<p>Country: </p> 
<p>Title: Hide your heart</p>
<p>Country: </p> 

如何显示我的国家/地区价值观。如果我从我的 XML 中删除 CDATA 标记,它就可以工作。但是,我无法修改 XML,因为它将来自外部提要。

谢谢 干杯

【问题讨论】:

  • 您使用哪种 XSLT 1.0 处理器?在这些 CDATA 部分中是否有格式正确的 XML?还是那会是 HTML?通常人们使用 CDATA 部分来转义不是 XML 的数据。
  • @MartinHonnen 我运行了以下代码: 结果是 Apache Software Foundation。从外观上看,它将是 CDATA 部分中的 HTML
  • 即使在 XSLT 2.0 中也很困难,尽管 Saxon 有扩展或在 XSLT 2.0 中完成了 HTML 解析器实现。使用 XSLT 1.0,如果您真的想解析内容以在其上执行 XPath,您将需要检查如何调用或实现扩展函数以集成 HTML 解析器。

标签: xml xslt xml-parsing xslt-1.0 cdata


【解决方案1】:

如前所述,源文档的作者不希望您将description 元素的内容解析为 XML - 否则他们不会将其标记为 CDATA 部分。

但是,您仍然可以将内容解析为文本 - 尽管它比其他方法更困难且更不可靠:

<xsl:template match="/">
    <xsl:for-each select="catalog/cd">
        <p>
            <xsl:text>Title: </xsl:text>
            <xsl:value-of select="title"/>
        </p> 
        <xsl:variable name="country-anchor" select="substring-before(substring-after(description, '&lt;b&gt;Country:&lt;/b&gt;'), '&lt;b&gt;')" />
        <p>
            <xsl:text>Country: </xsl:text>
            <xsl:value-of select="substring-before(substring-after($country-anchor, '&gt;'), '&lt;')"/>
        </p>
   </xsl:for-each>
</xsl:template>

如果您的处理链允许,更好的选择是分两遍进行转换:首先,禁用description 上的输出转义并将结果保存到文件;然后将生成的文件作为 XML 处理。

这两者都可以使用 XSLT 1.0 处理器来执行。

【讨论】:

    【解决方案2】:

    下面是如何使用 XSLT 2.0 和 Saxon 9 的商业版本以及 TagSoup HTML 解析器库http://home.ccil.org/~cowan/XML/tagsoup/ 的帮助以干净的方式完成它:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:saxon="http://saxon.sf.net/"
        xmlns:xhtml="http://www.w3.org/1999/xhtml"
        exclude-result-prefixes="xs saxon xhtml"
        version="2.0">
    
        <xsl:template match="/">
            <xsl:for-each select="catalog/cd">
                <p>Title: <xsl:value-of select="title"/></p> 
                <p>Country: <xsl:value-of select="saxon:parse-html(description)//xhtml:div/xhtml:b[. = 'Country:']/following-sibling::xhtml:a[1]"/></p>
            </xsl:for-each>
        </xsl:template>
    
    </xsl:stylesheet>
    

    作为替代方案,对于任何 XSLT 2.0 处理器,您都可以使用 David Carlisle 在 XSLT 2.0 本身中实现的 HTML 解析器:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:saxon="http://saxon.sf.net/"
        xmlns:xhtml="http://www.w3.org/1999/xhtml"
        xmlns:d="data:,dpc"
        exclude-result-prefixes="xs saxon xhtml d"
        version="2.0">
    
        <xsl:import href="https://raw.githubusercontent.com/davidcarlisle/web-xslt/master/htmlparse/htmlparse.xsl"/>
    
        <xsl:template match="/">
            <xsl:for-each select="catalog/cd">
                <p>Title: <xsl:value-of select="title"/></p> 
                <p>Country: <xsl:value-of select="d:htmlparse(description)//xhtml:div/xhtml:b[. = 'Country:']/following-sibling::xhtml:a[1]"/></p>
            </xsl:for-each>
        </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 很遗憾,我们使用的是 XSLT 版本 1
    【解决方案3】:

    CDATA 表示“字符数据”。 CDATA 标签的意思是“这里的东西可能看起来像标记,但不要被愚弄,我希望它被视为纯文本”。所以有人在这里嘘声;他们错误地使用 CDATA 来包含(至少对您而言)是标记而不是文本的内容。我不知道人们为什么要这样做,但唯一的补救办法是在处理数据之前修复损坏。

    有两种方法:

    (a) 使用纯文本处理工具(sed、awk、Perl)在 XML 解析之前简单地从文件中删除开始和结束 CDATA 标记。当然,只有知道 CDATA 部分的内容实际上是格式良好的 XML,才能这样做。

    (b) 处理提供的 XML 文档。 CDATA 部分将作为单个文本节点出现在您的 XSLT 代码中。要将其转换为节点树,您需要将其解析为 XML(CDATA 标记防止封闭的标记第一次被识别为标记)。例如,您可以使用 XSLT 3.0 parse-xml() 或 parse-xml-fragment() 函数,或调用扩展函数来执行此操作。同样,这依赖于知道内容是格式良好的 XML。如果是 HTML 而不是 XML(有时是这种情况),您可以调用 HTML 解析器而不是 XML 解析器。

    【讨论】:

      猜你喜欢
      • 2013-03-19
      • 2016-06-05
      • 2011-07-09
      • 2022-12-06
      • 1970-01-01
      • 2016-08-22
      • 2021-05-24
      • 1970-01-01
      • 2013-01-08
      相关资源
      最近更新 更多