XSLT apply-template select中的“@ * | node()”是什么意思?

时间:2012-06-23 06:44:14

标签: xml xslt

我读了一些XSLT示例,发现代码:

<xsl:apply-template select="@*|node()"/>

这是什么意思?

3 个答案:

答案 0 :(得分:41)

XPath表达式@* | node()选择属性节点(@*)和所有其他类型的XML节点(node())的 union

这是attribute::* | child::node()的简写。

在XSLT中,XPath是相对于上下文节点而默认的selection axischild轴,所以表达式

  • 选择上下文节点的所有属性和直接子节点(用作select="..."表达式时,例如在<xsl:apply-templates>中)
  • 匹配所有属性和其他节点,无论上下文如何(在match=""中用作<xsl:template>表达式时) - 请注意,选择节点和匹配之间存在差异它们:上下文节点只对选择很重要。

想象一下,以下节点是上下文节点:

<xml attr="value">[
  ]<child />[
  ]<!-- comment -->[
  ]<child>
    <descendant />
  </child>[
]</xml>

表达式node()不仅会选择两个<child>个节点,还会选择四个仅限空白的文本节点(为了可见性,由[]表示)和评论。未选择<descendant>

XML的一个特殊特征是属性节点不是它们所属元素的子元素(尽管属性的父元素是它所属的元素)。

这种不对称关系使得必须单独选择它们,因此@*

它匹配属于上下文节点的任何属性节点,因此也将选择attr="value"

|是XPath联合运算符。它从两个独立的节点集创建一个单节点集。

然后

<xsl:apply-templates>为每个选定的节点找到适当的<xsl:template>并为该节点运行它。这是我上面提到的模板匹配部分。

答案 1 :(得分:16)

添加Tomalak的优秀答案:

大多数人会在模板中看到<xsl:apply-template select="@*|node()"/>,就像这样

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

这称为identity rule或“身份模板”。

最基本和最强大的XSLT设计模式之一是使用和覆盖身份规则

如果转换仅包含标识规则,则转换的结果是源XML文档本身 - 这就是模板被称为“标识规则”的原因。

为什么会产生这种结果?

简短的回答是:因为XSLT处理模型。

更详细的说明必须从顶部开始:

node()

匹配任何元素,文本节点,注释或处理指令。文档 - (根) - 节点也与node()匹配。

我们可以想象任何文档树的“叶子”节点 - 这些节点本身没有子节点,例如文本节点,注释和处理指令。空元素也应该被视为叶节点。

最初选择标识规则来执行(应用)文档节点的所有子节点(这些是单个顶部元素以及它可能具有的任何注释或处理指令兄弟节点)。匹配的节点是浅层复制的,如果它是非元素叶节点,<xsl:apply-templates select="node()|@*"/>指令不会选择任何节点或属性。

如果匹配的节点是一个元素,则它被浅层复制,然后<xsl:apply-templates select="node()|@*"/>指令导致相同的模板(因为转换代码中没有任何其他模板)应用于它的每个属性和它的每个子节点。

这是驱动处理XML文档的每个节点的递归,直到到达叶节点或属性,<xsl:apply-templates select="node()|@*"/>选择没有子节点或属性节点。

答案 2 :(得分:7)

祝贺@Tomalak第一个正确答案。勾号应该是他的回答。我只想在他的回答中添加一些说明。

注一个

  

... @ * | node()选择...的联合

| operator不仅返回两个操作数的并集,而且按文档顺序排序并删除重复项。重复部分在这里不相关,因为没有重复删除,但排序部分值得注意。一个更正确的版本就是说......

  

... @ * | node()选择按文档顺序排序的联合...

注意两个

  

...以及所有其他类型的XML子节点(node())

这是大致正确的,但却具有误导性。当大多数人阅读&#34; XML子节点&#34;时,他们认为DOM意义上的子节点。但这不是被选中的。仅选择XDM节点。有关说明,请查看以下文档。

<?xml version="1.0" encoding="ISO-8859-1"?>
<root-element my-attrib="myattrib-vaue" xmlns:hi="www.abc.com"><child-element />
abc&apos;def
</root-element>

现在假设上下文项是&#39; root-element&#39;。 Tomalak的答案的读者被问到这样一个问题:&#34; @ * | node()&#34;?对于那些考虑DOM模型的人来说,Tomalak的答案意味着选择了6件事:

  • my-attrib属性
  • 节点空间属性(DOM中的true属性)
  • 子元素节点
  • &#39; abc&#39;位
  • 实体参考
  • &#39; def&#39;位。

但在XSLT中实际上并非如此。实际选择的是......

  • my-attrib属性
  • 子元素节点
  • XDM文本节点,是3个DOM文本节点的连接,如:&#34; abc&#39; def&#34;

所以更准确的陈述是......

XPath表达式@ * | node()选择以文档顺序排序的union(上下文项的属性节点和XDM意义上下文项的XML子节点)。 XD模型忽略DOM中的某些节点类型(如实体定义),并将连续的文本DOM节点连接到一个XDM文本节点中。