我对XSLT apply-template语句感到困惑。例如,在w3school。
http://www.w3schools.com/xsl/xsl_apply_templates.asp
对于陈述,
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
我的困惑是,
(1)<xsl:apply-templates/>
的功能是什么?它不包含任何要调用的特定模板。我认为它会匹配(返回)当前元素的所有直接子节点(当前节点的非直接子节点不会被返回,当前节点是根节点),不确定我是否正确?
(2)在(1)中返回所有匹配的节点后,XSLT处理器将执行的下一步操作是什么?
(3)在这个特定的示例中,根节点是目录还是其他更高级别的根?为什么?
提前谢谢, 乔治答案 0 :(得分:49)
有些事情会让你更容易理解答案:
首先,节点和元素不是同一个东西。元素是节点,但节点不一定是元素。您经常会发现人们可以互换使用这些术语。 XML中实际上有四种节点:元素,文本节点,处理指令和注释。 (属性不是真正的节点,我将在一秒钟内完成。)
在XSLT中,XML文档的根不是它的顶级元素;根是一个实际上并不存在的抽象。顶级元素是根的子元素。例如,这是一个格式良好的XML文档,其根目录有五个子节点,包括顶级元素:
<?xml-stylesheet href="mystyle.css" type="text/css"?>
<!-- this is a perfectly legitimate XML document -->
<top_level_element/>
五?看起来只有三个。我想我会让你弄明白其他两个是你自己。提示:在该示例中实际上可能有七个节点。
XPath表达式/
查找文档根目录,而不是顶级元素。在上述情况下,要查找顶级元素,您可以使用/top_level_element
或/*
。 (使用/*
来查找顶级元素总是安全的,因为文档根必须有一个元素子元素。)
如此掌握这些知识,让我们来看看apply-templates
的作用。它基本上执行两个步骤:首先,它构建一组节点。然后,对于每一个,它找到匹配的模板(从XSLT文件中的模板中)并将模板应用于它。正如您在其中一条评论中所观察到的那样,它在概念上非常类似于循环。
第一步使用select
属性。它提供了一个XPath表达式,用于构建将要应用模板的节点集。如果未提供select
属性,则它构建的列表是上下文节点的所有子项。 (“上下文节点”是当前模板应用于的节点。)
match
元素的template
属性用于第二步。样式表处理器查找match
属性与其尝试应用模板的节点匹配的所有模板。如果它找到多个,它会选择最具体的一个,例如:鉴于这些模板:
<xsl:template match="*"/>
<xsl:template match="foo"/>
<xsl:template match="foo[bar]"/>
具有foo
子元素的bar
元素将与第三个匹配,foo
元素与bar
元素将匹配第二个元素,并且{ {1}}元素将与第一个元素匹配。 (XSLT使用的实际方法定义为here;实际上,我已经使用XSLT近十年了,我从来不需要具体了解它是如何工作的,尽管它很有趣。)
如果没有找到匹配项,它将使用内置的默认模板作为节点类型 - 基本上,您可以假设任何XSLT转换隐式包含这些模板:
baz
拥有所有这些知识,您现在可以理解身份变换:
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()">
<xsl:copy/>
</xsl:template>
<xsl:template match="processing-instruction() | comment() | @*"/>
匹配任何节点或属性(请注意,属性不是节点,这就是需要<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
的原因),复制它,然后将模板应用于其所有子节点和属性。 (只有文档根和元素将具有子节点,并且只有元素将具有属性。)因为它是变换中唯一的模板,并且它匹配所有节点和属性,所以它将自身应用于所有子节点和属性。因此,它将源树中的所有内容复制到输出树。
如果您将此模板添加到身份识别转换:
@*
现在你有一个转换来复制源树中除 <xsl:template match="foo"/>
元素之外的每个节点 - 第二个模板匹配foo
元素(第一个模板也匹配,但是第二个foo
属性更具体,它是XSLT选择的一个属性,并且对它们没有任何作用。
鉴于这一切,你的具体问题的答案:
match
将模板应用于上下文节点的子节点。
在步骤1中未“返回”匹配的节点; XSLT处理器为每个模板找到一个模板并应用它。
在此示例中,上下文节点是文档根,是顶级元素及其外部的任何注释或处理指令是子级的抽象节点。
答案 1 :(得分:3)
<xsl:apply-templates />
将尝试查找与当前节点及其子节点匹配的模板。</body>
和</html>
)"/"
编辑:澄清1.
的示例;考虑your provided sample:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
Here we're at "root" node, just before "catalog" element.<br />
Let's enumerate this child nodes:
<ul>
<xsl:for-each select="*">
<li><xsl:value-of select="name()" /></li>
</xsl:for-each>
</ul>
<!-- Now, process "catalog" and ALL his child nodes -->
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="cd">
<p>
<!-- Find a template ONLY for title element -->
<xsl:apply-templates select="title"/>
<xsl:apply-templates select="artist"/>
</p>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:1)
xsl:apply-templates指示XSLT引擎将当前源文档子节点与样式表模板进行匹配,以便进一步处理。
答案 3 :(得分:1)
1)<xsl:apply-templates/>
调用遍历所有子节点(子节点)并调用匹配模板(如果有)。
2)在匹配所有节点之后,输出以下行,在这种情况下是
</body>
</html>
3)在示例目录中是根节点。
答案 4 :(得分:0)
XML元素包含 子 或 属性 。对于下面的XML,元素 book 有 child :: author (很快 author )和 attribute :: first (不久 @first )
<?xml version="1.0" encoding="UTF-8"?>
<book>
<author first="tom">Smith</author>
</book>
xsl:apply-templates表示为匹配节点的所有子节点执行模板,因此对于下面的模板,执行 author 的模板,但不是 @First
<xsl:template match="book">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="author">
<xsl:apply-templates/>
</xsl:template>