在XSL中匹配子元素

时间:2013-04-07 21:54:00

标签: xml xslt xpath

我以为我在this question的答案中看到了一个错误,并指出了它。我被告知我不正确,我的答案后来被删除了。

我仍然没有看到我错了。因此,我在这里发帖,希望有人能解释我对我的误解。

我回答的答案解释了apply-templates的使用。它包含以下XML和XSL,描述了模板的匹配方式:

<!-- sample XML snippet -->
<xml>
  <foo /><bar /><baz />
</xml>

<!-- sample XSLT snippet -->
<xsl:template match="xml">
  <xsl:apply-templates select="*" /> <!-- three nodes selected here -->
</xsl:template>

<xsl:template match="foo"> <!-- will be called once -->
  <xsl:text>foo element encountered</xsl:text>
</xsl:template>

<xsl:template match="xml/*"> <!-- will be called twice -->
  <xsl:text>other element countered</xsl:text>
</xsl:template>

我的评论是最后一个模板应该是:

<xsl:template match="*"> <!-- will be called twice -->
  <xsl:text>other element countered</xsl:text>
</xsl:template>

因为当前节点已经是<xml>

我被告知:

  

不,xml / *是一个匹配元素的子元素的模式   名字xml。

测试原始答案

但是,使用这个XML:

<xml>
  <foo /><bar /><baz />
</xml>

这个XSL样式表(填写上面的代码段):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

<xsl:template match="xml">
  <xsl:apply-templates select="*" /> <!-- three nodes selected here -->
</xsl:template>

<xsl:template match="foo"> <!-- will be called once -->
  <xsl:text>foo element encountered.&#xa;</xsl:text>
</xsl:template>

<xsl:template match="xml/*"> <!-- will be called twice -->
  <xsl:text>other element countered.&#xa;</xsl:text>
</xsl:template>

</xsl:stylesheet>

我明白了:

other element countered.
other element countered.
other element countered.

测试我的“已更正”版本

如果我用:

替换最后一个模板
<xsl:template match="*"> <!-- will be called twice -->
  <xsl:text>other element countered.&#xa;</xsl:text>
</xsl:template>

根据我的回答,我得到了:

foo element encountered.
other element countered.
other element countered.

这似乎是正确的。

我希望我的问题不会破坏任何指导方针,但我看不出我错了,希望有人能够更充分地解释它。

PS。我担心我对另一个问题的原始回复是作为答案发布的,而不是评论,因为我还没有足够的意见发表评论。我不确定最好的事情是做什么......

2 个答案:

答案 0 :(得分:6)

这是正确的,根据rules on the default priority of templates。匹配foo的模板具有默认优先级0,一个匹配*具有默认优先级-0.5,但一个匹配xml/*具有默认优先级0.5。 xml/*模板被认为比foo模板更具体,因此它可以在两者匹配时获胜。

所以你说得对,模板的匹配表达式需要*而不是xml/*,但不是正确的原因 - xml/*模板可以当前节点为apply-templates select="*"时匹配xml,并且它将应用于任何所选元素(因为它们都是xml的子项),除非有另一个模板具有显式priority大于0.5,可以优先。

答案 1 :(得分:4)

我是那个在另一个帖子里说你不正确的人,在仔细看了看之后,我可以看出你指出Tomalak犯了错误,但不是因为你给出的原因(如果我正确理解你的评论)。 match="xml/*" 匹配<xml>元素的子节点,无论当前上下文是否在调用<xml>时是apply-templates节点。在match=""表达式中,“当前节点”是应用模板的节点,而不是调用apply-templates的上下文,因此在此模板中,当前节点为foobarbaz。您可以从上面的实验中观察xml/*成功匹配xml的子元素,但实际上匹配它们比Tomalak说它更多。

match="xml/*"的问题在于它太具体并且与我认为Tomalak的意图相反。看来他认为这对于xml的孩子来说是一个无所不能的,但是正如Ian Roberts所解释的那样,这个模板的优先级高于{em> 。 {1}}模板,并捕获foo节点的所有子节点。

我知道现在不能写自己的评论令人沮丧,但很快就会有。并且可以创建自己的新问题来询问有关另一个线程的问题。你不应该创建答案来评论其他答案。