9

我以为我在这个问题的答案中看到了错误,并指出了这一点。有人告诉我我错了,我的答案后来被删除了。

我仍然不明白我是怎么错的。因此,我在这里发帖,希望有人能向我解释我的误解。

我回复的答案解释了应用模板的使用。它包含以下 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.

测试我的“更正”版本

If I replace the last template with:

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

as per my answer I get:

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

which would appear to be correct.

I hope my question doesn't break any guidelines, but I can't see that I'm wrong and am hoping someone can explain it more fully.

PS. I'm afraid my original response on the other question was posted as an answer, not a comment, as I don't have enough points to post comments yet. I wasn't sure what the best thing was to do...

4

2 回答 2

7

This is correct, according to the rules on the default priority of templates. A template matching foo has default priority 0, one matching * has default priority -0.5, but one matching xml/* has default priority 0.5. The xml/* template is considered more specific than the foo one, so it wins when either could match.

So you were right that the template's match expression needed to be * rather than xml/*, but not for the right reason - an xml/* template can match for an apply-templates select="*" when the current node is xml, and it will apply to any of those selected elements (since they are all children of xml) except where there is another template with an explicit priority greater than 0.5 that can take precedence.

于 2013-04-07T22:10:28.080 回答
4

I was the person who said you were incorrect in the other thread, and after looking at the matter more closely, I can see that you were correct in pointing out that Tomalak made a mistake, but not for the reasons you gave (if I'm understanding your comment correctly). match="xml/*" does match child nodes of the <xml> element, whether or not the current context was the <xml> node when apply-templates was called. In a match="" expression, the "current node" is the node on which templates are being applied, not the context where apply-templates was invoked, so in this template the current node would be foo, bar, and baz. You can observe from your own experimentation above that xml/* does succeed in matching child elements of xml, but in fact matches them more than Tomalak says it will.

The problem with match="xml/*" is that it's too specific and has the opposite effect of what I think Tomalak intended. It seems he meant for this to be a catch-all for children of xml that were not matched otherwise, but as Ian Roberts explains, this template winds up with a higher priority than the foo template, and catches all of the children of the xml node.

I know it's frustrating right now not being able to write comments of your own, but soon enough you will. And it is acceptable to create your own new question to ask a question about another thread. You just shouldn't create answers to comment on other answers.

于 2013-04-07T22:34:53.303 回答