XSL:循环问题

发布于 2024-10-20 21:41:27 字数 674 浏览 1 评论 0原文

我知道,作为一种函数式语言,XSL 没有传统的 for 循环(但有 for-each)之类的东西。

我正在尝试从可变数量的元素开始创建一个具有固定数量(7)的表。总之,我

<items>
    <item />
    <item />
    <item />
</item>

怎样才能把它变成

<table>
    <tr><item /></tr>
    <tr><item /></tr>
    <tr><item /></tr>
    <tr></tr>
    <tr></tr>
    <tr></tr>
    <tr></tr>
</table>

?使用 count() 很容易计算出我还需要 4 个empty ,但是如何做到这一点呢?使用 for 循环我可以轻松解决问题,或者修改 向其添加 4 个空元素,但是,作为 xsl 的新手,我什至无法做到这一点。

谢谢

I know that being a functional language, XSL doesn't have something like traditional for loops (but for-each).

I'm trying to create a table with a fixed number of (7) starting from a variable number of elements. In a word, I have

<items>
    <item />
    <item />
    <item />
</item>

How can I turn this into

<table>
    <tr><item /></tr>
    <tr><item /></tr>
    <tr><item /></tr>
    <tr></tr>
    <tr></tr>
    <tr></tr>
    <tr></tr>
</table>

? With count() it is easy to calculate that I need 4 more empty , but how to do this? With a for loop I could easily solve the problem, or maybe modifying <items> adding 4 empty elements to it, but, being new to xsl, i can't even do that.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

望笑 2024-10-27 21:41:27

您正在寻找递归解决方案。解决方案包括编写一个模板,当传入的计数小于您需要模板运行的次数时,该模板会调用自身。

IBM 在以下位置发布了一个很好的示例:

http://www.ibm。 com/developerworks/xml/library/x-tiploop.html

您的代码可能类似于:

<xsl:template name="itemLoop">

  <xsl:param name="count" select="0"/>

  <xsl:if test="$count < 7">
    <tr><xsl:apply-templates select="/items/item[$count]"/></tr>
    <xsl:call-template name="itemLoop">
      <xsl:with-param name="count" select="$count + 1"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>

You're looking for a recursion solution. The solution involves writing a template that calls itself when a passed in count is less than the number of times you need the template to run.

A good example is posted by IBM at:

http://www.ibm.com/developerworks/xml/library/x-tiploop.html

You're code may look something like:

<xsl:template name="itemLoop">

  <xsl:param name="count" select="0"/>

  <xsl:if test="$count < 7">
    <tr><xsl:apply-templates select="/items/item[$count]"/></tr>
    <xsl:call-template name="itemLoop">
      <xsl:with-param name="count" select="$count + 1"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>
奶气 2024-10-27 21:41:27

尽可能避免递归

在 XSLT 2.0 中,人们简单地写道:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:param name="pNumRows" select="7"/>
    <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="items">
     <table>
       <xsl:for-each select="1 to $pNumRows">
        <tr><xsl:copy-of select="$vDoc/items/item[current()]"/></tr>
       </xsl:for-each>
     </table>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<items>
    <item />
    <item />
    <item />
</items>

生成所需的正确结果:

<table>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr/>
   <tr/>
   <tr/>
   <tr/>
</table>

很少有人知道对于一个在 XSLT 1.0 中也可以避免大量情况的递归

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pNumRows" select="7"/>
 <xsl:param name="vDoc" select="/"/>


 <xsl:template match="items">
     <table>
       <xsl:for-each select=
             "(document('')//node())[not(position() > $pNumRows)]">
         <xsl:variable name="vPos" select="position()"/>

         <tr><xsl:copy-of select="$vDoc/items/item[position()=$vPos]"/></tr>
       </xsl:for-each>
   </table>
 </xsl:template>
</xsl:stylesheet>

这称为 Piez 方法,可以阅读它此处

记住:递归比简单迭代慢得多 - 如果列表具有相当大的长度(大约 1000 或更多)并且不采取特殊的编程措施,它也往往会因堆栈溢出而崩溃。

It is best to always avoid recursion, when possible.

In XSLT 2.0 one simply writes:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:param name="pNumRows" select="7"/>
    <xsl:variable name="vDoc" select="/"/>

 <xsl:template match="items">
     <table>
       <xsl:for-each select="1 to $pNumRows">
        <tr><xsl:copy-of select="$vDoc/items/item[current()]"/></tr>
       </xsl:for-each>
     </table>
 </xsl:template>
</xsl:stylesheet>

and when this transformation is applied to the provided XML document:

<items>
    <item />
    <item />
    <item />
</items>

the wanted correct result is produced:

<table>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr>
      <item/>
   </tr>
   <tr/>
   <tr/>
   <tr/>
   <tr/>
</table>

Very few people know that for a large number of cases one can avoid recursion in XSLT 1.0, too:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:param name="pNumRows" select="7"/>
 <xsl:param name="vDoc" select="/"/>


 <xsl:template match="items">
     <table>
       <xsl:for-each select=
             "(document('')//node())[not(position() > $pNumRows)]">
         <xsl:variable name="vPos" select="position()"/>

         <tr><xsl:copy-of select="$vDoc/items/item[position()=$vPos]"/></tr>
       </xsl:for-each>
   </table>
 </xsl:template>
</xsl:stylesheet>

This is called the method of Piez and one can read about it here.

Remember: Recursion is much slower than simple iteration -- it also tends to crash with stack overflow if the list has considerable length (around 1000 or more) and special programmatic measures are not taken.

时光暖心i 2024-10-27 21:41:27

您应该在这里看看这个问题:

如何对类别中的元素进行计数并将其与 XSLT 中的其他类别进行比较

那里讨论了相同的问题(标题没有提到这一点)并且有很多很好的答案关于如何解决这个问题。

You should have a look at this question here:

How to count elements in categorys and compare it with other categorys in XSLT

There is the same problem discussed there (the title doesn't mention this) and there are many good answers on how to solve this.

梦在深巷 2024-10-27 21:41:27

这是一个示例表,可以满足您的要求。我使用 count 计算出有多少项,然后计算出需要创建多少个空行。我使用 for_loop 模板。

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <table>
            <xsl:for-each select="//items/item">
                <tr><item/></tr>
            </xsl:for-each>

            <xsl:variable name="itemCount" as="xs:integer" select="count(//items/item)" />
            <xsl:call-template name="for_loop">
                <xsl:with-param name="i">
                    <xsl:value-of select="0" />
                </xsl:with-param>
                <xsl:with-param name="count">
                    <xsl:value-of select="7-$itemCount" />
                </xsl:with-param>
            </xsl:call-template>

        </table>
    </xsl:template>

    <xsl:template name="for_loop">
        <xsl:param name="i" />
        <xsl:param name="count" />
        <xsl:if test="$i < $count">
            <tr></tr>
        </xsl:if>
        <xsl:if test="$i < $count">
            <xsl:call-template name="for_loop">
                <xsl:with-param name="i">
                    <xsl:value-of select="$i + 1" />
                </xsl:with-param>
                <xsl:with-param name="count">
                    <xsl:value-of select="$count" />
                </xsl:with-param>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

Here is an example sheet which does what you want. I work out how many items there are using count and then how many empty rows I need to create. I use a for_loop template.

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <table>
            <xsl:for-each select="//items/item">
                <tr><item/></tr>
            </xsl:for-each>

            <xsl:variable name="itemCount" as="xs:integer" select="count(//items/item)" />
            <xsl:call-template name="for_loop">
                <xsl:with-param name="i">
                    <xsl:value-of select="0" />
                </xsl:with-param>
                <xsl:with-param name="count">
                    <xsl:value-of select="7-$itemCount" />
                </xsl:with-param>
            </xsl:call-template>

        </table>
    </xsl:template>

    <xsl:template name="for_loop">
        <xsl:param name="i" />
        <xsl:param name="count" />
        <xsl:if test="$i < $count">
            <tr></tr>
        </xsl:if>
        <xsl:if test="$i < $count">
            <xsl:call-template name="for_loop">
                <xsl:with-param name="i">
                    <xsl:value-of select="$i + 1" />
                </xsl:with-param>
                <xsl:with-param name="count">
                    <xsl:value-of select="$count" />
                </xsl:with-param>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文