For loops与apply-templates

时间:2011-06-14 11:39:30

标签: xml xslt xslt-1.0

我最近开始在我的一些XML文档中使用XSLT,我有一些问题。我在下面添加代码。在代码中,我有一个匹配电子书元素的模板。然后我想列出写这本书的所有作者。我为每个循环使用a,但我也可以应用模板。我什么时候使用循环以及何时使用模板时看不清楚。

另一个问题是,当你现在不会在你正在编写它的元素的其他子元素时,只说say-templates是正常的。在我的情况下,在模板中匹配文档根我说的是apply-templates。然后它找到了电子书,它是唯一的孩子,但我可以有一个“书籍”元素区分“常规”书籍和电子书籍然后它只列出书籍的字符数据。如果我只想在我的最终文档中使用电子书,那么我就需要编写apply-templates select =“ebooks”。那么这是一个案例,它取决于你对文件的了解程度如何?

谢谢,这是我的代码(这只是为了练习):

XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="ebooks.xsl"?>
<ebooks>
    <ebook>
        <title>Advanced Rails Recipes: 84 New Ways to Build Stunning Rails Apps</title>
        <authors>
            <author><name>Mike Clark</name></author>
        </authors>
        <pages>464</pages>
        <isbn>978-0-9787-3922-5</isbn>
        <programming_language>Ruby</programming_language>
        <date>
            <year>2008</year>
            <month>5</month>
            <day>1</day>
        </date>
        <publisher>The Pragmatic Programmers</publisher>
    </ebook>
    ...

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="/">
        <html>
            <head>
                <title>Library</title>
            </head>
            <body>
                <xsl:apply-templates />            
            </body>
        </html>    
    </xsl:template>

    <xsl:template match="ebooks">
        <h1>Ebooks</h1>
        <xsl:apply-templates>
            <xsl:sort select="title"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ebook">
        <h3><xsl:value-of select="title"/></h3>
        <xsl:apply-templates select="date" />

        <xsl:for-each select="authors/author/name">
            <b><xsl:value-of select="."/>,</b>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="date">
        <table border="1">
            <tr>
                <th>Day</th>
                <th>Month</th>
                <th>Year</th>
            </tr>
            <tr>
                <td><xsl:value-of select="day"/></td>
                <td><xsl:value-of select="month"/></td>
                <td><xsl:value-of select="year"/></td>
            </tr>
        </table>
    </xsl:template>

</xsl:stylesheet>

4 个答案:

答案 0 :(得分:9)

这个问题有点争论,但这是我的看法。

  

我什么时候看不清楚   循环以及何时使用模板。

我会说你应该尽可能经常地避免for-each,而不是apply-templates

使用for-each通过添加嵌套级别使您的程序更加复杂,并且还可以重新使用for-each块内的代码。使用apply-templates将(在完成时)生成更灵活和模块化的XSLT。

另一方面:如果你编写一个复杂度有限且重用性或模块化不是问题的样式表,使用for-each可能会更快更容易理解(对于人类读者/维护者)。所以这部分是个人偏好的问题。

在你的情况下,我会发现这个优雅:

<xsl:template match="ebook">
  <!-- ... -->
  <xsl:apply-templates select="authors/author" />
  <!-- ... -->
</xsl:template>

<xsl:template match="authors/author">
  <b>
    <xsl:value-of select="name"/>
    <xsl:if test="position() &lt; last()">,</xsl:if>
  </b>
</xsl:template>

提出其他问题

  

另一个问题是,当你知道你正在编写元素的其他孩子时,只说apply-templates是正常的。

当你知道这个元素中永远不会有任何孩子时,写apply-templates毫无意义。

如果做得好,XSLT能够灵活处理不同的输入。如果您希望某些时候可以成为孩子,那么apply-templates就不会受到伤害。

一个简单的apply-templates没有select是非特定的,无论是哪个(即:所有这些)和都按照什么顺序 (即:输入文档顺序)节点将被处理。因此,您最终可能会处理您从未想要处理的节点或您之前已经处理过的节点。

由于无法为未知节点编写合理的模板,因此我倾向于避免非特定 apply-templates,并在输入更改时调整样式表。

答案 1 :(得分:5)

  

我为每个循环使用a来做,但是我   也可以将模板应用于它。一世   什么时候看不清楚   循环以及何时使用模板。

如果确切知道如何处理<xsl:for-each> ,则使用<xsl:for-each>绝不会有害。

麻烦的是许多XSLT的新手在命令式编程方面都有<xsl:for-each>作为他们最喜欢的PL中“循环”的替代品,并认为它允许他们执行不可能的事情 - 比如说递增计数器或已定义的<xsl:variable>的任何其他修改。

XSLT 1.0中<xsl:for-each>的一个必不可少的用途是更改当前文档 - 为了能够在文档上使用key()函数,这通常是必需的,与当前源不同例如,XML文档可以有效地访问驻留在自己的xml文档中的查找表。

另一方面,使用<xsl:template><xsl:apply-templates>更加强大和优雅。

以下是两种方法之间最重要的差异

  1. xsl:apply-templatesxsl:for-each更加丰富和深刻,甚至 只是因为我们不知道将在节点上应用什么代码 选择 - 在一般情况下,此代码将有所不同 节点列表的不同节点。

  2. 将应用的代码 可以在xsl:apply template写完之后写出来 那些不了解原作者的人。

  3. 如果XSLT没有<xsl:apply-templates>指令,则无法在XSLT中实现FXSL library高阶函数(HOF)

      

    另一个问题是,这是正常的   当你(k)现在说申请模板   那里不会有其他孩子   你正在写它的元素

    <xsl:apply-templates/>
    

    是:

    的简写
    <xsl:apply-templates select="child::node()"/>
    

    即使当前节点还有其他孩子,你也不在乎,你仍然可以使用短<xsl:apply-templates>并拥有另一个模板:

    <xsl:template match="*"/>
    

    此模板忽略(“删除”)任何元素。您应该使用更具体的模板覆盖它(在XSLT中,通常,更具体的模板具有更高的优先级,并且选择通过与同一节点匹配的特定于较少的模板进行处理):

    <xsl:template match="ebook">
      <!-- Necessary processing here -->
    </xsl:template>
    

    我通常不使用<xsl:template match="*"/>但我使用另一个匹配(并忽略)每个文本节点的模板:

     <xsl:template match="text()"/>
    

    这通常与使用<xsl:template match="*"/>具有相同的效果,因为XSLT处理没有匹配模板的节点的方式。在任何此类情况下,XSLT都会在其中称为“默认处理”的内置模板

    XSLT默认处理以元素为根的子树的结果是输出该元素的所有文本节点后代的连接(按文档顺序)。

    因此,使用<xsl:template match="text()"/>阻止任何文本节点的输出具有与阻止使用<xsl:template match="*"/>处理元素的输出相同的(null)输出结果。

    摘要

    1. 模板和<xsl:apply-templates>指令是XSLT如何实现和处理多态的。

    2. 本着XSLT处理模型的精神,使用更多通用模板匹配大类节点并对它们进行一些默认处理,然后用更具体的模板覆盖通用模板,这些模板匹配并仅处理我们的节点感兴趣的。

    3. 参考:查看整个帖子: http://www.stylusstudio.com/xsllist/200411/post60540.html

答案 2 :(得分:4)

通常在XSLT中读取xsl:for-each并不是必需的,但仅在某些情况下。通常,您应该可以使用xsl:apply-templates方式。

例如,您可以在不xsl:for-each的情况下轻松调整转换,更改ebook模板,如下所示:

<xsl:template match="ebook">
    <h3><xsl:value-of select="title"/></h3>
    <xsl:apply-templates select="date" />
    <xsl:apply-templates select="authors/author/name"/>
</xsl:template>

并添加以下内容:

<xsl:template match="name">
    <b><xsl:value-of select="."/>,</b>
</xsl:template>

回答你的问题:

  
    

我看不清楚何时使用循环和何时使用模板。

  

在XSLT中,差异被称为“推”式与“拉”,你可以在其中阅读好的IBM developerWorks和@ XML.com

我的规则是,只有当你无法想象如何摆脱它们时才使用循环:))。

  
    

另一个问题是,当你(k)现在不会有你正在编写它的元素的其他孩子时,只是说apply-templates是正常的

  

当你“说”

<xsl:apply-templates />

您只是告诉处理器将模板应用于所有当前上下文节点的子节点。所以这取决于你是否想要这个:)。您可以拥有不同的孩子,仍然需要将模板应用于其中任何一个。这取决于具体情况。

当您只使用<xsl:apply-templates />时,通常需要注意内置规则的应用方式,并最终根据需要将其关闭。

例如,在您的情况下,您也可以使用:

<xsl:template match="ebook">
    <h3><xsl:value-of select="title"/></h3>
    <xsl:apply-templates />
</xsl:template>

<xsl:template match="isbn|programming_language|publisher|pages|title"/>

希望这有帮助。

答案 3 :(得分:3)

一般来说,我同意Dimitre的回答。建议初学者使用xsl:apply-templates而不是xsl:for-each的主要原因是,一旦他们对xsl:apply-templates感到舒适且经验丰富,他们就不会发现难以在两个结构之间做出决定,然而,在他们获得这种体验之前,他们会不恰当地使用xsl:for-each。

xsl:apply-templates相对于每个人的主要好处是代码能够更好地适应不断变化的文档结构和不断变化的处理要求。很难将这种好处卖给那些只想在一起修改一些代码并且不关心三年后世界将会是什么样的人,但这是一个非常真实的好处。