带递归模板的无限循环

时间:2013-12-21 22:35:06

标签: xml templates xslt recursion

我需要创建一个模板,用于格式化包含高尔夫球手在球场上每个洞的得分的表格单元格...

  • 两个名为parScore和holeScore的参数。 parScore参数包含 球场上选定球洞的标准杆。 holeScore参数包含 高尔夫球手在球洞上取得的成绩。
  • 一个选择元素,用于测试holeScore参数是否等于, 小于或大于parScore参数。如果holeScore小于 parScore,写下面的代码: holeScore 其中holeScore是holeScore参数的值。如果holeScore更高 比parScore,写代码: holeScore 否则,写代码: holeScore

以下是我编写的代码,但似乎陷入无限循环,我不确定我是否正确调用模板或问题是什么?

<xsl:template name="formatHole">
    <xsl:param name="parScore" />
    <xsl:param name="holeScore" select="0" />

    <!-- Check to see if cells parameter is greater than 0-->
    <xsl:choose>
        <xsl:when test="$holeScore &lt; $parScore">
            <td class="low"><xsl:value-of select="$holeScore" /></td>
        </xsl:when>

        <xsl:when test="$holeScore > $parScore">
            <td class="high"><xsl:value-of select="$holeScore" /></td>
        </xsl:when>

        <xsl:otherwise>
            <td><xsl:value-of select="$holeScore" /></td>
        </xsl:otherwise>
    </xsl:choose>

    <xsl:call-template name="formatHole">
        <xsl:with-param name="parScore" select="$holeScore - 1" />
        <xsl:with-param name="holeScore" select="$parScore" />
    </xsl:call-template>    
</xsl:template>

以下是xml代码的片段...

<course>
   <par holeNumber="1">4</par>
   <par holeNumber="2">4</par>
   <par holeNumber="3">5</par>
   <par holeNumber="4">3</par>
   <par holeNumber="5">4</par>
   <par holeNumber="6">4</par>
   <par holeNumber="7">5</par>
   <par holeNumber="8">3</par>
   <par holeNumber="9">4</par>
   <par holeNumber="10">4</par>
   <par holeNumber="11">5</par>
   <par holeNumber="12">4</par>
   <par holeNumber="13">3</par>
   <par holeNumber="14">4</par>
   <par holeNumber="15">5</par>
   <par holeNumber="16">4</par>
   <par holeNumber="17">3</par>
   <par holeNumber="18">4</par>
</course>

<golfer>
   <name>Brett Bierson</name>
   <round roundNumber="1">
      <score holeNumber="1">4</score>
      <score holeNumber="2">4</score>
      <score holeNumber="3">5</score>
      <score holeNumber="4">2</score>
      <score holeNumber="5">4</score>
      <score holeNumber="6">4</score>
      <score holeNumber="7">5</score>
      <score holeNumber="8">4</score>
      <score holeNumber="9">4</score>
      <score holeNumber="10">4</score>
      <score holeNumber="11">3</score>
      <score holeNumber="12">4</score>
      <score holeNumber="13">3</score>
      <score holeNumber="14">4</score>
      <score holeNumber="15">5</score>
      <score holeNumber="16">5</score>
      <score holeNumber="17">3</score>
      <score holeNumber="18">3</score>
   </round>

3 个答案:

答案 0 :(得分:3)

无需使用call-templates执行此操作。您需要的所有信息都在每个节点上。你拥有的是a pull (rather than a push) XSLT template。对于每个score,您需要知道的是,您需要针对该给定的孔号对par进行检查,因此只需检查它。

在下面的模板中,除了在课程中搜索该洞的相应数据外,我们只是单独查看得分。这意味着我们如何对待得分与其他得分相同。

<xsl:template match="score">
    <xsl:variable name="holeScore" select="." />
    <xsl:variable name="holeNum" select="@holeNumber" />    
    <xsl:variable name="parScore" select="/data/course/par[@holeNumber = $holeNum]" />
    <tr>
      <td><xsl:value-of select="@holeNumber"/></td>
      <xsl:choose>
        <xsl:when test="$holeScore &amp;lt; $parScore">
            <td class="low"><xsl:value-of select="$holeScore" /></td>
        </xsl:when>

        <xsl:when test="$holeScore &amp;gt; $parScore">
            <td class="high"><xsl:value-of select="$holeScore" /></td>
        </xsl:when>

        <xsl:otherwise>
            <td><xsl:value-of select="$holeScore" /></td>
        </xsl:otherwise>
      </xsl:choose>
    </tr>
</xsl:template>

我们可以在渲染表时轻松调用此方法,只需使用apply-templates获取高尔夫球手在其课程中所拥有的每个分数:

    <xsl:template match="golfer">
      <h2>Scores for <xsl:value-of select="name"/></h2>
        <table>
          <tr>
              <td>Hole</td><td>Score</td>
          </tr>
          <xsl:apply-templates select="./round/score"/>
        </table>
    </xsl:template>

以完整形式,此转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
      <html>
      <head>
        <style>
          .low {
            background-color:red;
          }
          .high {
            background-color:green;
          }
        </style>
      </head>
      <body>
          <xsl:apply-templates select="/data/golfer"/>
      </body>
      </html>
    </xsl:template>

    <xsl:template match="golfer">
      <h2>Scores for <xsl:value-of select="name"/></h2>
        <table>
          <tr>
              <td>Hole</td><td>Score</td>
          </tr>
          <xsl:apply-templates select="./round/score"/>
        </table>
    </xsl:template>

    <xsl:template match="score">
        <xsl:variable name="holeScore" select="." />
        <xsl:variable name="holeNum" select="@holeNumber" />    
        <xsl:variable name="parScore" select="/data/course/par[@holeNumber = $holeNum]" />
        <tr>
          <td><xsl:value-of select="@holeNumber"/></td>
          <xsl:choose>
            <xsl:when test="$holeScore &amp;lt; $parScore">
                <td class="low"><xsl:value-of select="$holeScore" /></td>
            </xsl:when>

            <xsl:when test="$holeScore &amp;gt; $parScore">
                <td class="high"><xsl:value-of select="$holeScore" /></td>
            </xsl:when>

            <xsl:otherwise>
                <td><xsl:value-of select="$holeScore" /></td>
            </xsl:otherwise>
          </xsl:choose>
        </tr>
    </xsl:template>
</xsl:stylesheet>

应用于此文档(我必须将其包装在额外的标记中以使其成为有效的XML):

<data>
<course>
   <par holeNumber="1">4</par>
   <par holeNumber="2">4</par>
   <par holeNumber="3">5</par>
   <par holeNumber="4">3</par>
   <par holeNumber="5">4</par>
   <par holeNumber="6">4</par>
   <par holeNumber="7">5</par>
   <par holeNumber="8">3</par>
   <par holeNumber="9">4</par>
   <par holeNumber="10">4</par>
   <par holeNumber="11">5</par>
   <par holeNumber="12">4</par>
   <par holeNumber="13">3</par>
   <par holeNumber="14">4</par>
   <par holeNumber="15">5</par>
   <par holeNumber="16">4</par>
   <par holeNumber="17">3</par>
   <par holeNumber="18">4</par>
</course>

<golfer>
   <name>Brett Bierson</name>
   <round roundNumber="1">
      <score holeNumber="1">4</score>
      <score holeNumber="2">4</score>
      <score holeNumber="3">5</score>
      <score holeNumber="4">2</score>
      <score holeNumber="5">4</score>
      <score holeNumber="6">4</score>
      <score holeNumber="7">5</score>
      <score holeNumber="8">4</score>
      <score holeNumber="9">4</score>
      <score holeNumber="10">4</score>
      <score holeNumber="11">3</score>
      <score holeNumber="12">4</score>
      <score holeNumber="13">3</score>
      <score holeNumber="14">4</score>
      <score holeNumber="15">5</score>
      <score holeNumber="16">5</score>
      <score holeNumber="17">3</score>
      <score holeNumber="18">3</score>
   </round>
</golfer>
</data>

提供此文件:

<html>
    <head>
        <style>
                  .low {
                    background-color:red;
                  }
                  .high {
                    background-color:green;
                  }
                </style>
        </head>
        <body>
            <h2>Scores for Brett Bierson</h2>
            <table>
                <tr>
                    <td>Hole</td>
                    <td>Score</td>
                </tr>
                <tr>
                    <td>1</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>2</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>3</td>
                    <td>5</td>
                </tr>
                <tr>
                    <td>4</td>
                    <td class="low">2</td>
                </tr>
                <tr>
                    <td>5</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>6</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>7</td>
                    <td>5</td>
                </tr>
                <tr>
                    <td>8</td>
                    <td class="high">4</td>
                </tr>
                <tr>
                    <td>9</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>10</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>11</td>
                    <td class="low">3</td>
                </tr>
                <tr>
                    <td>12</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>13</td>
                    <td>3</td>
                </tr>
                <tr>
                    <td>14</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>15</td>
                    <td>5</td>
                </tr>
                <tr>
                    <td>16</td>
                    <td class="high">5</td>
                </tr>
                <tr>
                    <td>17</td>
                    <td>3</td>
                </tr>
                <tr>
                    <td>18</td>
                    <td class="low">3</td>
                </tr>
            </table>
        </body>
    </html>

看起来像这样:

Example table from the given data

答案 1 :(得分:0)

最后,您的模板会调用您的模板:

<xsl:template name="formatHole">
    [...]
    <xsl:call-template name="formatHole">
        <xsl:with-param name="parScore" select="$holeScore - 1" />
        <xsl:with-param name="holeScore" select="$parScore" />
    </xsl:call-template>   
</xsl:template>

这可以解释为什么它没有结束。与JavaScript中的方式相同:

function foo() {
    foo();
}

不会结束。或者更有可能J​​avaScript版本以堆栈溢出结束。 XSLT代码没有结束,因为我认为XSLT解释器执行tail call optimization。 (它变成了迭代。)

答案 2 :(得分:-2)

我对高尔夫一无所知,所以我只是在这里猜测。看起来您想要为一轮中的每个分数创建一个单元格,并将其与课程中相应的holeNumber的par相比较。

您的模板存在一些问题:首先,您永远不会检查在0下运行的迭代器(尽管您确实有评论说您应该这样做)。接下来,您选择的holeScore作为迭代器是没有意义的:您需要从1到18进行迭代,而不是从4或5到0进行迭代。此外,在每次迭代时都要与相同的par进行比较。

现在,假设这是在一轮的上下文中完成的,你可以用更简单的方式完成。首先,将以下内容放在样式表的开头,在任何模板之外:

<xsl:key name="par" match="par" use="@holeNumber" />

接下来,在回合的背景下,执行以下操作:

<tr>
    <td><xsl:value-of select="@roundNumber" /></td>
    <xsl:call-template name="createCells"/>
</tr>

最后,这是被调用的模板:

<xsl:template name="createCells">
    <xsl:for-each select="score">
        <xsl:variable name="par" select="key('par', @holeNumber)" />
        <xsl:choose>
            <xsl:when test=". &lt; $par">
            <td class="low"><xsl:value-of select="." /></td>
            </xsl:when>

            <xsl:when test=". > $par">
            <td class="high"><xsl:value-of select="." /></td>
            </xsl:when>

            <xsl:otherwise>
            <td><xsl:value-of select="." /></td>
            </xsl:otherwise>
        </xsl:choose>   
    </xsl:for-each>
</xsl:template>

请注意,这假设每一轮都有18个分数。如果这不是一个有效的假设,那么需要使用带有迭代器的递归模板。