这是一直让我对XSLT感到困惑的事情:
例:
<person>
<firstName>Deane</firstName>
<lastName>Barker</lastName>
</person>
Run Code Online (Sandbox Code Playgroud)
这是XSLT的一个片段:
<!-- Template #1 -->
<xsl:template match="/">
<xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/>
</xsl:template>
<!-- Template #2 -->
<xsl:template match="/person/firstName">
First Name: <xsl:value-of select="firstName"/>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
关于这个的两个问题:
那么,"后来的"模板是否会受到"早期"模板中发生的事情的影响,或者它们是否对源文档进行操作,而忽略了"先前"转换为它们的内容?(所有这些单词都在引号中,因为当我真的不知道如何确定模板顺序时,我发现很难讨论基于时间的问题...)
在上面的例子中,我们有一个在根节点("/")上匹配的模板 - 当它完成执行时 - 基本上从输出中删除了所有节点.在这种情况下,这是否会抢占所有其他模板,因为在第一个模板完成后没有任何内容可以匹配?
到目前为止,我一直关注以后的模板没有执行,因为他们操作的节点没有出现在输出中,但反过来呢?"早期"模板是否可以创建"后期"模板可以执行某些操作的节点?
在与上面相同的XML上,考虑这个XSL:
<!-- Template #1 -->
<xsl:template match="/">
<fullName>
<xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/>
</fullName>
</xsl:template>
<!-- Template #2 -->
<xsl:template match="//fullName">
Full Name: <xsl:value-of select="."/>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
模板#1创建一个名为"fullName"的新节点.模板#2在同一节点上匹配.模板#2会执行,因为当我们到达模板#2时,输出中存在"fullName"节点吗?
我意识到我对XSLT的"禅"一无所知.到目前为止,我的样式表包含一个匹配根节点的模板,然后从那里完全是程序性的.我厌倦了这样做.我宁愿真正理解XSLT,因此我的问题.
Eva*_*enz 83
我喜欢你的问题.你对你还不了解的内容非常清楚.你只需要把东西绑在一起.我的建议是你读过"XSLT如何工作",这是我写的一章,准确地解决了你所问的问题.我很想知道它是否能为你们联系起来.
不太正式,我会采取措施回答你的每一个问题.
- 模板的执行顺序是什么,以及
- 当它们执行时,它们是否匹配(a)原始源XML,或者(b)XSLT的当前输出到那一点?
在XSLT处理的任何给定点,在某种意义上,有两个上下文,您将其标识为(a)和(b):您在源树中的位置以及您在结果树中的位置.您在源树中的位置称为当前节点.当您选择要使用XPath处理的任意节点集时,它可以在源树周围进行更改和跳转.但是,从概念上讲,您永远不会以同样的方式"跳转"结果树.XSLT处理器以有序的方式构建它; 首先,它创建结果树的根节点; 然后它添加子项,按文档顺序构建结果(深度优先).[您的帖子激励我再次获取XSLT实验的软件可视化......]
样式表中模板规则的顺序永远不重要.您无法通过查看样式表来了解模板规则将以何种顺序实例化,实例化规则的次数,甚至是否完全实例化.(match="/"是一个例外;你总是可以知道它会被触发.)
我假设模板#1将首先执行.我不知道为什么我会这么想 - 是不是因为它首先出现在文件中?
不.即使你把它放在文档的最后,它也会被称为第一个.模板规则顺序永远不重要(除非在错误条件下,当您有多个具有相同优先级的模板规则匹配同一节点时;即使这样,它对于实现者来说是可选的,您永远不应该依赖这种行为).它首先被调用,因为每当你运行XSLT处理器时总会发生的第一件事是虚拟调用<xsl:apply-templates select="/"/> .一个虚拟调用构造整个结果树.它外面没有任何事情发生.您可以通过定义模板规则来自定义或"配置"该指令的行为.
模板#2会执行吗?它匹配源XML中的节点,但是当我们到达此模板时(假设它运行第二个),"firstName"节点将不在输出树中.
模板#2(也没有任何其他模板规则)永远不会被触发,除非您<xsl:apply-templates/>在match="/"规则中的某个地方有呼叫.如果你没有,那么除了match="/"触发之外没有模板规则.可以这样考虑:要使模板规则被触发,它不能只匹配输入中的节点.它必须匹配您选择处理(使用<xsl:apply-templates/>)的节点.相反,它将继续匹配节点,因为您选择处理节点的次数.
[
match="/"模板] 会抢先执行所有其他模板,因为在第一个模板完成后没有任何内容可以匹配吗?
该规则优先于包括<xsl:apply-templates/>在其中的其他地方.仍然有很多节点可以在源树中处理.他们总是在那里,适合采摘; 根据需要处理每一个.但使用模板规则处理它们的唯一方法是调用<xsl:apply-templates/>.
到目前为止,我一直关注以后的模板没有执行,因为他们操作的节点没有出现在输出中,但反过来呢?"早期"模板是否可以创建"后期"模板可以执行某些操作的节点?
并不是"早期"模板创建了一个要处理的新节点; 这是一个"早期"模板反过来使用相同的指令(<xsl:apply-templates)处理来自源树的更多节点.您可以将其视为递归调用相同的"函数",每次使用不同的参数(由上下文和select属性确定要处理的节点).
最后,你得到的是对同一个"function"(<xsl:apply-templates>)的递归调用的树形结构堆栈.而这个树结构与你的实际结果是同构的.不是每个人都意识到这一点,或者以这种方式思考过它; 那是因为我们还没有任何有效的可视化工具......
模板#1创建一个名为"fullName"的新节点.模板#2在同一节点上匹配.模板#2会执行,因为当我们到达模板#2时,输出中存在"fullName"节点吗?
不.进行处理链的唯一方法是以这种方式明确地设置它.创建一个变量,例如,$tempTree包含新<fullName>元素,然后像这样处理它<xsl:apply-templates select="$tempTree">.要在XSLT 1.0中执行此操作,您需要使用扩展函数(例如exsl:node-set())包装变量引用,但在XSLT 2.0中它将按原样工作.
无论您是从原始源树还是在构造的临时树中处理节点,您都需要明确说明要处理的节点.
我们没有涉及的是XSLT如何获得其所有隐式行为.您还必须了解内置模板规则.我一直在编写样式表,甚至没有为根节点(match="/")包含明确的规则.相反,我依赖于根节点的内置规则(将模板应用于子节点),这与元素节点的内置规则相同.因此,我可以忽略输入的大部分,让XSLT处理器自动遍历它,只有当它遇到我感兴趣的节点时才会做一些特别的事情.或者我可以编写一个递归复制所有内容的规则(称为标识转换),仅在必要时覆盖它,以对输入进行增量更改.在您阅读"XSLT如何工作"之后,您的下一个任务是查找"身份转换".
我意识到我对XSLT的"禅"一无所知.到目前为止,我的样式表包含一个匹配根节点的模板,然后从那里完全是程序性的.我厌倦了这样做.我宁愿真正理解XSLT,因此我的问题.
我为你鼓掌 现在是时候采取"红色药丸":阅读"XSLT如何工作"
模板始终与源XML匹配.因此,顺序并不重要,除非2个或更多模板匹配相同的节点.在这种情况下,有点违反直觉,触发了最后一个匹配模板的规则.
| 归档时间: |
|
| 查看次数: |
24452 次 |
| 最近记录: |