tags:

views:

261

answers:

4

Dear all,

How to use for loop 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"/>
  <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

A: 

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>
Cagdas
we can not do like thisbecause the <tr> can not close properly and its showing error
Pramodh
You're absolutely right about the "<tr>" problem. CDATA trick easily solves it. You can check my edited code above. I tested with XML Notepad and it transforms successfully.
Cagdas
This is absolutely the wrong way to do this.
Robert Rossney
but its giving the correct output.
Pramodh
+3  A: 

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <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>
Dimitre Novatchev
+3  A: 

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.

Robert Rossney
A: 
<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> 
Pramodh
its giving correct output but is it the right way?
Pramodh