我确信这是一个非常基本的问题,但无论如何都要进行!我已经读过XSLT中文本和属性节点的内置模板规则是
<xsl:template match="text()|@*">
<xsl:value-of select="."/>
</xsl:template>
但是对于源文件
<?xml version="1.0"?>
<booker>
<award>
<author blah="test">Aravind Adiga</author>
<title>The White Tiger</title>
<year>2008</year>
</award>
</booker>
和XSLT
<?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:stylesheet>
我在Visual Studio中应用变换得到以下输出。有人可以解释为什么我没有在输出中看到“测试”吗?
Aravind Adiga
白虎
2008
答案 0 :(得分:6)
因为元素的内置规则不会将模板应用于元素自己的属性,而只应用于它的子元素。如果要以遍历子元素的相同方式遍历属性(这可能是一个人为任务),您需要定义自己的默认值:
<xsl:template match="*">
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:template>
答案 1 :(得分:6)
从评论中解决这个问题:
谢谢,我不需要真正去做,我只是想了解规则。所以基本上内置规则的@ *部分永远不会被调用,除非它被显式调用?
在这种情况下,我们有两个默认规则:
<xsl:template match="text()|@*">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="/|*">
<xsl:apply-templates/>
</xsl:template>
处理文档时,第二个模板与root和apply-templates匹配。 apply-templates的默认设置是选择所有子节点(属性,容易混淆,不是子节点)。您永远不会选择要处理的任何属性,因为唯一的apply-templates
会以默认形式显示。
因此,如果您选择任何属性(如Vincent Marchetti所做的那样),它将由第一个提到的默认模板处理。
答案 2 :(得分:2)
主要规则是 - 属性根本没有身份 - 它们只能作为附加到节点的横向位来访问。在你有一个节点之前,将它们视为不存在是很好的。您还可以将它们视为XPath和XSLT世界中的完全二等公民。每次在选择条件中使用它们时,就像在SQL中从连接切换到光标一样,每次使用“for”而不是“apply”时,也会发生同样的情况。
另一种说法 - 你拥有的唯一真实,高效的“索引”是文档中所有XPath的一个(.Net实际上构建了XPaths的Hashtable =&gt;常量时间匹配)。 “apply”具有特权的原因是它保证了纯粹的功能处理 - 你可以通过在没有同步和没有内存共享的单独线程上运行匹配的所有东西 - 你只需将结果连接起来。
第三种方式来看待它,这是一个延伸,想象你的标签是SQL表,并且你只有代理PK-s和FK-s - 你可以真正选择的其他东西除了“所有来自T1和所有相关的他们来自T2“。对于任何体面的SQL引擎来说,这就像是一个0成本的努力 - 它只是逐项读取一个好的索引,因为它的结构与你的查询是1-1。其他一切都要花费更多。
一旦选择了标签并且模板匹配并运行,那么只需获取属性值就可以了 - 只要你只是转换/渲染它们。 XPath结束时的Attrib测试也相当便宜 - 因为选择了最终的标记/节点,现在它只是一个小过滤器。
因此,XSLT引擎和XPath选择一般都有很好的理由完全忽略属性 - perf。