Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

XSLT column

Status
Not open for further replies.

largegrape

Programmer
May 6, 2004
9
0
0
US
How do I transform the following:

<root>
<item>
<title>1</title>
</item>
<item>
<title>2</title>
</item>
<item>
<title>3</title>
</item>
<item>
<title>4</title>
</item>
</root>

to look like this:

1 3
2 4

A solution that can configure the number of rows and/or columns would be nice but at this point I'm desparate for a quick solution.

Thanks.
 
I have done this before...but luckily found a cleaner example at this site:


I mucked with it a little so the wording made more sense and the column numbers was a variable at the top of the xslt.

Code:
<?xml version='1.0' encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] version="1.0">
    <xsl:output method="html" indent="yes"/>
    <xsl:variable name="columnNum" select="'3'"/>
    <xsl:template match="/">
        <xsl:apply-templates select="/root"/>
    </xsl:template>
    <!-- The template for the items to be printed into a table. This
     is where the <table> tag gets printed. -->
    <xsl:template match="root">
        <!-- table rows are built with general purpose table routine: "makeRows"
       "nodeSet" is the nodeset of items to be put in cells
       "counter" is always 1   -->
        <table border="1">
            <xsl:call-template name="makeRows">
                <xsl:with-param name="nodeSet" select="item"/>
                <xsl:with-param name="counter" select="1"/>
            </xsl:call-template>
        </table>
    </xsl:template>
    <!-- The template for printing the table rows -->
    <xsl:template name="makeRows">
        <xsl:param name="nodeSet"/>
        <!-- print c cols (one row) -->
        <tr>
            <xsl:call-template name="makeCols">
                <xsl:with-param name="nodeSet" select="$nodeSet[position() &lt; ($columnNum + 1)]"/>
                <xsl:with-param name="counter" select="1"/>
            </xsl:call-template>
        </tr>
        <!-- recurse to print the remaining rows -->
        <xsl:if test="$nodeSet[position() &gt; $columnNum]">
            <xsl:call-template name="makeRows">
                <xsl:with-param name="nodeSet" select="$nodeSet[position() &gt; $columnNum]"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    <!-- The template for printing the table columns -->
    <xsl:template name="makeCols">
        <xsl:param name="nodeSet"/>
        <xsl:param name="counter"/>
        <!--print out c (number of) cells-->
        <xsl:if test="not($counter &gt; $columnNum)">
            <td>
                <xsl:if test="$nodeSet">
                    <xsl:value-of select="$nodeSet[1]/title"/>
                </xsl:if>
            </td>
            <!-- if there are any left, recurse-->
            <xsl:call-template name="makeCols">
                <xsl:with-param name="nodeSet" select="$nodeSet[position() != 1]"/>
                <xsl:with-param name="counter" select="$counter + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Hope that helps

-jay
 
Hi Jay,

I appreciate the help but what I need is vertical columns:

1 6
2 7
3 8
4 9
5 10

not

1 2
3 4
5 6
7 8
9 10

Do you or anyone else out there know how to do this?

Thanks,
LG
 
BTW, I found some code to do horizontal columns with less code, if you're interested (see below). But I still need to know how to get vertical columns working.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl=" <xsl:eek:utput method="html" indent="yes" />
<xsl:param name="cols" select="3"/>

<!-- Selects the ART-elements, which are at the beginning of a row. -->
<xsl:template match="items">
<table border="1">
<xsl:apply-templates select="item[position() mod $cols = 1]" mode="row"/>
</table>
</xsl:template>

<!-- Selects the first ART of a row and the rest in this row. -->
<xsl:template match="item" mode="row">
<tr>
<xsl:apply-templates select=". | following-sibling::item[position() &lt; $cols]" mode="cell"/>
</tr>
</xsl:template>

<!-- Add the cells. -->
<xsl:template match="item" mode="cell">
<td><xsl:value-of select="description"/></td>
</xsl:template>

</xsl:stylesheet>
 
I can't think of a difficult way to do this, so here's a simple one: just calculate how many nodes there's gone be, divide by 2 (round off upwards) and you know the number of rows. For each node <= halfway start a row and display that node with its neighbour - whose position is the number-of-rows further.
Code:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
   <xsl:output method="html" encoding="Windows-1252" />
	
   <xsl:variable name="NumberOfRows" select="round(count(//item) div 2)" />

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

   <xsl:template match="root">
      <table>
         <xsl:apply-templates select="item[position() &lt; $NumberOfRows + 1]" />
      </table>
   </xsl:template>

   <xsl:template match="item">
      <tr>
         <xsl:variable name="position" select="position()+$NumberOfRows" />
         <xsl:apply-templates select="*|../item[position()=$position]/*" />
      </tr>
   </xsl:template>

   <xsl:template match="title">
      <td>
         <xsl:value-of select="." />
      </td>
   </xsl:template>
</xsl:stylesheet>
 
Hey Jel,

I just tried out your xslt file, it didn't produce the results i was looking for. This is what i got:

13 24 3 4

Someone out there must know how to get what I need, please help me!!!

Thanks,
LG
 
I'm surprised...
It looks like your parser doesn't read all x-path expressions. Try and debug with this:
Code:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
   <xsl:output method="html" encoding="Windows-1252" />
    
   <xsl:variable name="NumberOfRows" select="round(count(//item) div 2)" />

   <xsl:template match="/">
      <html>
         <body>
         	<xsl:text>variable NumberOfRows is: </xsl:text>
         	<xsl:value-of select="$NumberOfRows"/>
            <xsl:apply-templates />
         </body>
      </html>
   </xsl:template>

   <xsl:template match="root">
      <table border="1">
         <xsl:apply-templates select="item[position() &lt; $NumberOfRows + 1]" />
      </table>
   </xsl:template>

   <xsl:template match="item">
      <tr>
         <xsl:variable name="position" select="position()+$NumberOfRows" />
      	<td><xsl:text>My position is: </xsl:text><xsl:value-of select="position()"/>
      	<xsl:text> but I'll also print for position: </xsl:text><xsl:value-of select="$position"/>
      	</td>
         <xsl:apply-templates select="*|../item[position()=$position]/*" />
      </tr>
   </xsl:template>

   <xsl:template match="title">
      <td>
         <xsl:value-of select="." />
      </td>
   </xsl:template>
</xsl:stylesheet>
It should result in this html:
Code:
<html>
<body>
variable NumberOfRows is: 2
<table border="1">
<tr>
<td>My position is: 1 but I'll also print for position: 3</td>
<td>1</td>
<td>3</td>
</tr>
<tr>
<td>My position is: 2 but I'll also print for position: 4</td>
<td>2</td>
<td>4</td>
</tr>
</table>
</body>
</html>
Enjoy
 
I'm using IE6. I have item.xml and item.xslt. In the item.xml I have:

<?xml-stylesheet type="text/xsl" href="item.xslt"?

Then I just open the item.xml file using IE6. IE6 does client side transformation and the following is the result:

variable NumberOfRows is: 2 My position is: 1 but I'll also print for position: 313 My position is: 2 but I'll also print for position: 424 My position is: 3 but I'll also print for position: 53 My position is: 4 but I'll also print for position: 64

Please help.

Thanks,
LG
 
It seems that <xsl:template match="item"> is executed for all items, instead of only nrs 1 and 2. Did you omit <xsl:apply-templates select="item[position() &lt; $NumberOfRows + 1]" />, or put in a <xsl:template match="*"> somewhere?


 
Nope, just copied and pasted your code into a new file.
 
I'm sorry, I really don't know. I haven't been doing much with IE lately, so I might be a bit out of touch. Just tried above with IE6 with SP1, and it works OK.
 
That is weird...

Jel, I just tested this code in IE 6.0.2 and Mozilla 1.7, and also through Java parsers Saxon and Xalan and received the correct results.

largegrage, has your XML file changed?

Not sure what version your MSXML is, but that should be updated when you update IE. Have you tried running this in an IDE like XML Spy?

-jay
 
My bad, for some reason my xml file got changed. It does work thanks jay and jel. But I noticed that with this solution I can only do 2 columns. Could you help me out with a solution that will make the number of ROWS configurable?

ie:
if total items = 15 and ROWS is set to 3

1 4 7 10 13
2 5 8 11 14
3 6 9 12 15

Thanks,
LG

BTW: Can you guys recommend a good book on Advanced XSLT?
 
Never mind, I just figured it out, thx anyways.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl=" <xsl:eek:utput method="html" encoding="Windows-1252" />

<xsl:variable name="NumberOfRows" select="2" />

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

<xsl:template match="root">
<table border="1">
<xsl:apply-templates select="item[position() &lt; $NumberOfRows + 1]" mode="row"/>
</table>
</xsl:template>

<xsl:template match="item" mode="row">
<tr>
<xsl:variable name="position" select="position()+$NumberOfRows" />
<xsl:apply-templates select=".|following-sibling::item[position() mod $NumberOfRows = 0]/." mode="cell"/>
</tr>
</xsl:template>

<xsl:template match="item" mode="cell">
<td>
<xsl:value-of select="title" /><br/>
<xsl:value-of select="description"/>
</td>
</xsl:template>
</xsl:stylesheet>
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top