开发者

How to use for loop in xslt

开发者 https://www.devze.com 2022-12-29 23:19 出处:网络
How to use xsl:for-each in xslt to get value iteratively from an xml file and to dispaly it in table fromat

How to use xsl:for-each in xslt to get value iteratively from an xml file and to dispaly it in table fromat

For example: the xml file is like

<order>
  <item name ="a"/>
  <item name ="b"/>  
  <item name ="c"/>
  <item name ="d"/>
  &l开发者_如何学Ct;item name ="e"/>
  <item name ="f"/>
  <item name ="g"/>
</order>

and the output should be

  a    b    c   d

  e    f    g

the loop should count the item and if it is divisble by 4 it

should close the current row and add a new row and so on..

i'm using the following xslt for this

but i can not display it in table format

   <xsl:template match="/">
    <html>
    <body>
     <xsl:call-template name ="incr">
        <xsl:with-param name ="value">1</xsl:with-param>
        <xsl:with-param name ="limit">
          <xsl:value-of select ="count(//item)"/>
        </xsl:with-param>
      </xsl:call-template>
  </body>
</html>
</xsl:template >
<xsl:template name="incr">
  <xsl:param name="value"/>
  <xsl:param name ="limit"/>
  <xsl:if test ="$value!=$limit+1">
    <xsl:value-of select ="//item[$value]/@name"/>
    <xsl:if test ="$value mod 4 =0">
      <br/>
      <br/>
    </xsl:if>
    <xsl:call-template name ="incr">
      <xsl:with-param name ="value" select ="$value+1"/>
      <xsl:with-param name ="limit" select ="$limit"/>
    </xsl:call-template>
  </xsl:if>

</xsl:template>

please help me to do this

Thanks in advance


This transformation:

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

 <xsl:variable name="vNumCols" select="4"/>

 <xsl:template match="/*">
  <table>
   <xsl:for-each select=
     "item[position() mod $vNumCols = 1]">

     <tr>
       <xsl:for-each select=
       ". | following-sibling::*
                 [not(position() >= $vNumCols)]">
        <td><xsl:value-of select="@name"/></td>
       </xsl:for-each>
     </tr>
   </xsl:for-each>
  </table>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document, produces the desired correct results:

<table>
   <tr>
      <td>a</td>
      <td>b</td>
      <td>c</td>
      <td>d</td>
   </tr>
   <tr>
      <td>e</td>
      <td>f</td>
      <td>g</td>
   </tr>
</table>


The way to think about problems of any complexity in XSLT is not "how would I write a program to produce Y, given X as input?" but rather, "given output Y, what X am I going to transform to produce it?" It's not an easy principle to grasp (or articulate), but once you get it, what seem like hard problems in XSLT become trivial.

If the output is a series of tr elements, like this:

<tr>
   <td>a</td><td>b</td><td>c</td>
</tr>
<tr>
   <td>d</td><td>e</td><td>f</td>
</tr>
<tr>
   <td>g</td><td>h</td><td>i</td>
</tr>
<tr>
   <td>j</td><td/><td/>
</tr>

there are, in essence, four output elements. So there must be four input elements.

The first question is, which four? Pretty clearly, it's going to be the 1st, 4th, 7th, and 10th - that is, every 3 elements, starting with the first. So your starting point is to transform those four elements:

<xsl:apply-templates select="/order/item[position() mod 3 = 1]"/>

Okay, and now that we've selected every third element, how are we going to create a tr out of it and the elements right after it? Using the following-sibling axis:

<xsl:template match="item">
   <tr>
      <td><xsl:value-of select="@name"/></td>
      <td><xsl:value-of select="following-sibling::item[1]/@name"/></td>
      <td><xsl:value-of select="following-sibling::item[2]/@name"/></td>
   </tr>
</xsl:template>

That's good, as far as it goes. But there's a fair amount of duplicated code, and a lot you have to modify if you want (say) to change the number of columns from 3 to 6. You can eliminate the duplicated code by making another template:

<xsl:template match="item">
   <tr>
      <xsl:apply-templates select="@name | following-sibling::item[position() &lt;= 3]/@name"/>
   </tr>
</xsl:template>

<xsl:template match="@name">
   <td><xsl:value-of select="."/></td>
</xsl:template>

And you can parameterize the number of columns by putting it in a variable, as Dimitre has done in his example.


I am not 100% sure but the code below should do it:

<table>
    <tr>
    <xsl:for-each select="//order/item">
        <td>
        <xsl:value-of select ="current()/@name"/>
        </td>
    <xsl:if test="position() mod 4 = 0">
    <xsl:text disable-output-escaping="yes"><![CDATA[</tr><tr>]]></xsl:text>
    </xsl:if>
    </xsl:for-each>
    <xsl:variable name="item_count_mod4" select="count(//order/item) mod 4"/>
    <xsl:choose>
      <xsl:when test="$item_count_mod4 = 1">
        <td></td><td></td><td></td>
      </xsl:when>
      <xsl:when test="$item_count_mod4 = 2">
        <td></td><td></td>
      </xsl:when>
      <xsl:when test="$item_count_mod4 = 3">
        <td></td>
      </xsl:when>
      <xsl:otherwise>
      </xsl:otherwise>
    </xsl:choose>
    </tr>
</table>


<table> 
 <tr> 
  <xsl:for-each select="//order/item"> 
   <td> 
    <xsl:value-of select ="current()/@name"/> 
   </td> 
   <xsl:if test="position() mod 4 = 0"> 
    <xsl:text disable-output-escaping="yes"><![CDATA[</tr><tr>]]></xsl:text> 
   </xsl:if> 
  </xsl:for-each> 
 </tr> 
</table> 
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号