XSLT应用模板问题

时间:2009-12-29 09:25:37

标签: xml xslt

我对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)在这个特定的示例中,根节点是目录还是其他更高级别的根?为什么?

提前谢谢, 乔治

5 个答案:

答案 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选择的一个属性,并且对它们没有任何作用。

鉴于这一切,你的具体问题的答案:

  1. match将模板应用于上下文节点的子节点。

  2. 在步骤1中未“返回”匹配的节点; XSLT处理器为每个模板找到一个模板并应用它。

  3. 在此示例中,上下文节点是文档根,是顶级元素及其外部的任何注释或处理指令是子级的抽象节点。

答案 1 :(得分:3)

  1. <xsl:apply-templates />将尝试查找与当前节点及其子节点匹配的模板。
  2. 返回所有匹配的节点后,XSL处理器将输出那些结束标记(即</body></html>
  3. 在目录之前有一个根节点,与"/"
  4. 匹配

    编辑:澄清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>

  • text() node Smith 是元素 author 的子元素,因此 xsl:apply-templates text()节点的调用模板:

<xsl:template match="author"> <xsl:apply-templates/> </xsl:template>