我无法在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,因为它将来自外部供稿。
由于 干杯
答案 0 :(得分: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, '<b>Country:</b>'), '<b>')" />
<p>
<xsl:text>Country: </xsl:text>
<xsl:value-of select="substring-before(substring-after($country-anchor, '>'), '<')"/>
</p>
</xsl:for-each>
</xsl:template>
更好的选择 - 如果您的处理链允许 - 将在两次传递中进行转换:首先,禁用description
上的输出转义并将结果保存到文件中;然后将生成的文件作为XML处理。
这两个都可以使用XSLT 1.0处理器执行。
答案 1 :(得分:0)
以下是如何使用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>
答案 2 :(得分:0)
CDATA表示&#34;字符数据&#34;。 CDATA标签意味着&#34;这里的东西可能看起来像标记,但不要被愚弄,我希望它被视为纯文本&#34;。所以有人在这里兴奋;他们错误地使用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解析器。