考虑这个XML:
<person>
<name>
<firstName>James</firstName>
<lastName>Bond</lastName>
</name>
</person>
然后考虑这个XSL:
<xsl:template match="//name">
[do stuff]
</xsl:template>
<xsl:template match="//firstName">
[do stuff]
</xsl:template>
我在说的第一个模板(“//名”)的存在是正确的“隐藏”的第二个模板(“//名字”)。 我知道这是真实的(我在发布前测试这一点),但我想获得和理解的一般规则。
以来...
- 它(“//名”)是较不具体
- 将首先匹配
- 它不叫“应用模板”
......第二个模板将不会被处理。
什么是这个逻辑的机制,以及它如何预测? 当“//名”模板处理,所以处理器不知何故逻辑“勾选”所有的子元素不是需要处理? 它们是否被认为“完成”,因为他们的父母已得到处理?
如果我要确保第二模板运行,是否有任何其他方式以外,以确保“应用模板”被称为第一模板?
再次,我知道有解决这个办法,我只是想了解它背后的理论/理由。
通过michael.hor257k和伊恩·罗伯茨所提供的答案是正确的,完整的,但因为你似乎仍然有问题,这也许可以解释它以不同的方式可能会有所帮助。
首先,请注意你的图案//基本上没有影响; 你的模板将不得不如果匹配模式被写入相同的含义"name"
和"firstName"
。 如果在你的脑海里,你一直在想的是,//信号可能影响控制流的任何信息,这将有利于打消这个想法。
其次,请注意,在任何输入/处理/输出树木或文档语言,所述语言的设计者可以假设一种“推送”的处理(该处理器通过输入读出并在所述输入处理的每个项目,从而产生输出时和作为合适的;当输入完成后,该过程完成),或者说是一种“拉”的处理(该处理器产生由项目所需的输出项目,咨询所述输入根据需要,输出完成时,该过程完成) 。
在语言不容许的数据的重排序,这两个图案相吻合:输入以线性顺序被处理从开始到结束,并输出被以线性顺序从开始到结束生产。
在像XSLT,或者它的前身DSSSL语言,如果你考虑在其中输入项目的处理顺序和在输出项目产生的序列两者之间的区别是明显的。 在一个简单的(或:幼稚)实现一键语言(如DSSSL的树,以树的转变过程)中,输入项目按顺序处理,并且输出计算出的顺序,缓冲,直到完成。 在一拉语言(如XSLT),输出被计算,以便和输入被缓冲,以便它可以以任意顺序被访问。
需要注意的是,使用“推”和“拉”这里是不太一样的感觉中,许多XSLT程序员应用这些方面XSLT样式表-在语言级别,正如我刚才描述的这些条款,XSLT是拉语言。 天真的实现缓冲所有输入。 有一定的讽刺意味,因为内XSLT,“推”样式通常比“拉”的样式更地道。
也是我说的是天真的实现注意:XSLT的规范是纯粹的声明,并且处理器可以在任何他们喜欢的顺序做的事情。 但最简单,最容易实施的策略是,以评估描述样式表的输出表现,为了。 默认情况下,输出全部由模板正文的文档节点匹配模板说明。
为您展示XML,在样式表控制流(假设你只有两种选择模板)会是这样的,在一个简单的,天真的XSLT实现的:
如果你已经正常调用它(即不带任何选项来覆盖缺省行为),处理器寻找一个模板文档节点匹配。 由于在样式表中没有匹配模板/,默认的规则适用,它由
<xsl:apply-templates/>
或者,明确提供的默认值:
<xsl:apply-templates select="child::node()"/>
该处理器将栈上的模板,并开始执行它。 模板中的唯一一件事就是应用模板调用,所以这是处理器做什么。
现在处理器推动的所有子/栈上(以相反的文档顺序); 让我们假设为了具体,这些儿童(1)的“人”元件,和(2)由一个新行,随后的“人”元素的文本节点中。 对于反过来他们每个人,该处理器旨在匹配的模板。 在这一点上,“人”的要素是在堆栈的顶部,因此处理器查找匹配的模板。
该处理器发现匹配的“人”元素的样式没有模板,所以它使用已被伊恩·罗伯茨,描述的默认模板,什么也不做,但通话
<xsl:apply-templates select="child::node()"/>
处理器将对于“人”元件(默认的)模板到堆栈并开始执行它。 这个模板什么也不做,但呼吁儿童应用模板。
现在处理器推栈上的“人”元素的所有孩子。 栈现在包含:
- 包含零个或多个空格或制表,换行,和两个空格的文本节点(在“人”元素的开始)
- 一个“名”元素
- 包含零个或多个空格或制表符和一个换行(“名称”和“人”的结束标签之间)文本节点
- 模板的“人”元素,这表明执行指令指针应继续遵循“应用模板”指令。
- 含有如下在输入“人”的结束标记(它被放置在栈上,在步骤2)换行文本节点
- 模板的文档根目录节点,这表明执行指令指针应该在调用“应用模板”后恢复。
既然没有模板匹配堆栈的顶部的文本节点,处理器遵循默认的规则,其本质要求
<xsl:value-of select="."/>
因此处理器写出文本节点的字符串值,并弹出堆栈。
的“name”元素现在是在堆栈的顶部; 该处理器现在看起来匹配它的模板。 它发现在样式表中的第一个模板,并推动在堆栈上的模板。
处理器计算匹配模板的主体 - 中显示的样式表的版本,这是由含有一些空白,文本“[做的东西]”,和一些空白的文本节点。 它这个文本节点的字符串值写入到输出,和(已完成了对模板的评价)弹出堆栈。
栈上的下一个节点是“姓名”元素之后的空白节点。 样式表没有模板匹配,所以该处理器采用默认的文本节点模板,并复制字符串值输出。 现在处理器与这就是“人”元素的最后一个子文本节点完成的,因此它会弹出堆栈。
堆栈的顶部,现在是由相匹配的“人”元素(默认)模板占据。 处理器继续在由指令指针,这是调用“应用模板”后表示的点。 有没有别的模板中的身体,所以模板正文已全面进行了评估。 该处理器与模板完成,并弹出其堆栈。
堆栈现在提出了“人”元素之后的空白点。 样式表没有模板匹配,所以该处理器采用默认的文本节点模板,复制字符串值的输出,并弹出堆栈。
在堆栈上的唯一的事,现在是匹配的文档的根节点的默认模板。 我们定位在“应用模板”指令后,所以有没有别的事可做。 处理器弹出堆栈。
该堆栈现在是空的,并且样式表的评估已经完成。
刚刚给出的描述应理解,当然,与一粒盐:它描述控制的逻辑流,并且不一定事件的序列中的给定的实现。 例如,在实践中的处理器可以通过使用尾调用优化形式,以避免在离开堆栈上模板如果指令指针到达模板的端节省堆栈空间。 更一般地,XSLT有一种纯粹的声明性语义,“这种情况发生这种情况,那么”,说的样式表评估的任何讨论是短手“做这将是这种情况发生的一种方式,那么” - 该规范不限制在事情发生的时间顺序,只输出的结构。
简化的,因为它是评价这种模式会帮助你理解为什么你的第二个模板不会被调用。 你认为原因是喜忧参半:
它无关的匹配模式“// name”和“//名字”的相对特异性 - 因为他们不能匹配相同的节点,这两种模式的相对特异性永远不能成为一个问题。 (在任何情况下,两个匹配模式有相同程度的特异性和两个模板具有相同的默认优先级。)
它是与“名字”元素第一只针对什么是“被先匹配”的一个非常特殊的(不是很精确)概念被匹配可能意味着。 时间关系不是由XSLT规范规定,因此“第一”是不是一个真正的定义或定义的概念。 这是真的,在样式表中的任何评价,在“名称”元素的模板,可以说是的模板“的firstName”元素之前匹配,但只有在这个意义上,一个模板匹配,其它永远没有匹配(我们仍在等待它来搭配,我们会永远等待)。 对于“名称”火灾的模板,因为总会有地方正在执行的模板点包含具有其价值包括“名称”元素节点“选择”属性的“应用模板”指令。 对于“的firstName”模板永远不会触发,因为这永远不会发生的“的firstName”元素:它从来没有出现在任何“选择”属性对任何“应用模板”的价值进行评估。
正如伊恩·罗伯茨指出,如果你想这两个模板火,在样式表是类似于当前的越好,解决方案是增加<xsl:apply-templates/>
到模板“名字”元件。
[附录]读者努力让他们的头周围的控制流可能会发现埃文伦茨的回答一个相关的问题很有帮助。
导致模板火的唯一的事情就是打电话xsl:apply-templates
。 看起来这是在许多情况下,自动的原因是,XSLT定义默认模板规则( XSLT 2.0 , XSLT 1.0 )时,有一个特定的节点匹配没有明确的模板火灾。 元素节点的默认规则是有效的
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
如果你定义一个明确的模板为特定的节点是由你来决定什么时候(或者实际上是否) apply-templates
到它的孩子。 对于某些类型的转换,你可能想要把孩子处理的结果的特定元素里面 ,你可能需要把它之前或之后的其他情形。 XSLT不会试图和第二猜测这一点。
在你的榜样,你没有一个明确的模板person
所以默认规则适用,适用模板的三个子节点person
元素(之前的空白文本节点name
元素的name
本身,而空白文本后节点name
)。 对于name
有一个明确的模板,使火灾,并且由于它并不apply-templates
,以其他任何东西,尽可能的递归去的。
以来...
- 它(“//名”)是较不具体
- 将首先匹配
- 它不叫“应用模板”
......第二个模板将不会被处理。
正确答案是#3。
要理解这一点,你必须明白,处理器(即内置的模板规则)的默认行为是遍历整个输入树并访问每个节点。
什么当它到达一个节点的处理器确实取决于匹配该节点的模板。 如果模板不告诉处理器继续穿越,则该分支的其余部分被放弃。 (请注意,默认模板并应用模板到当前节点的子节点)。
如果我要确保第二模板运行,是否有任何其他方式以外,以确保“应用模板”被称为第一模板?
是。 你可以从第三模板应用第二个模板。 你不局限于应用模板,只是当前节点的孩子。 您可以应用模板当前节点的兄弟姐妹,祖先,后裔......或者在输入树的完全不同的分支节点连。
文章来源: Why does processing a parent element's template prevent the processing of child element templates?