Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old November 25th, 2003, 01:24 PM
Registered User
 
Join Date: Oct 2003
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to lukemedway_uk
Default xslt looping with tables...

I wonder if anyone can help me. I'm trying to do a simple loop which will loop a certain number of columns and then loop down onto a new row, inside a table.

Easily done in asp, and i've seen it in xslt before, but not understood it, fully. So i was hoping someone might have an example they could just quickly run through and explain what each part does...?

Thanks

 
Old November 26th, 2003, 01:57 AM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via Yahoo to armmarti
Default

As I understand, you needn't to do any transformation; all you need is just to output a table. So, if this is true, look what can you do:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:param name="c" select="3"/>
    <xsl:param name="r" select="4"/>

    <xsl:template match="/">
        <xsl:call-template name="output-rows">
            <xsl:with-param name="columns" select="$c"/>
            <xsl:with-param name="rows" select="$r"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="output-rows">
        <xsl:param name="columns"/>
        <xsl:param name="rows"/>

        <xsl:choose>
                <xsl:when test="$rows > 0">
                    <tr>
                        <xsl:call-template name="output-columns">
                            <xsl:with-param name="columns" select="$columns"/>
                            <xsl:with-param name="rows" select="$rows"/>
                        </xsl:call-template>
                    </tr>            
                    <xsl:call-template name="output-rows">
                        <xsl:with-param name="columns" select="$columns"/>
                        <xsl:with-param name="rows" select="$rows - 1"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise/> 
        </xsl:choose>
    </xsl:template>

    <xsl:template name="output-columns">
        <xsl:param name="columns"/>
        <xsl:param name="rows"/>

        <xsl:choose>
                <xsl:when test="$columns > 0">
                    <td>
                        <xsl:element name="cell">
                            <xsl:value-of select="concat('[', $r - $rows + 1, ', ', $c - $columns + 1, ']')"/>
                        </xsl:element>
                    </td>            
                    <xsl:call-template name="output-columns">
                        <xsl:with-param name="columns" select="$columns - 1"/>
                        <xsl:with-param name="rows" select="$rows"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise/> 
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>
This stylesheet can be applied to any XML document (to itself, for example).
The stylesheet has 2 recursive templates; one to output rows and other to output columns. It's just simulating simple looping construct through recursive structure and nothing more. If you have any concrete question, let me know please.

Regards,
Armen
 
Old November 26th, 2003, 07:24 AM
Registered User
 
Join Date: Oct 2003
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to lukemedway_uk
Default

Thank you, I understand what's going on as a whole. But I'm not sure I understand what exactly is going on here though...

<xsl:element name="cell">
   <xsl:value-of select="concat('[', $r - $rows + 1, ', ', $c - $columns + 1, ']')"/>
</xsl:element>

... As you can tell, I'm very new to xml/xslt. :p


 
Old November 26th, 2003, 08:01 AM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via Yahoo to armmarti
Default

Quote:
quote:Originally posted by lukemedway_uk
 Thank you, I understand what's going on as a whole. But I'm not sure I understand what exactly is going on here though...

<xsl:element name="cell">
   <xsl:value-of select="concat('[', $r - $rows + 1, ', ', $c - $columns + 1, ']')"/>
</xsl:element>

... As you can tell, I'm very new to xml/xslt. :p


Since the templates decrement the values in each recursive pass, we have to do that(concat('[', $r - $rows + 1, ', ', $c - $columns + 1, ']')) to get values (1,1) (1,2).... (2,1) (2,2)... in this sequence. Otherwise (concat('[', $rows, ', ', $columns, ']')) will give the "opposite" sequence, i.e. (4,3) (4,2) (4,1) (3,3) ...

Regards,
Armen
 
Old December 19th, 2003, 01:53 AM
Authorized User
 
Join Date: Dec 2003
Posts: 11
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to btado
Default

Hi Armmarti,

I'm trying to accomplish something similar, except that I need to do data transformation. Here's some example xml:
<products>
<product><title>123</title><price>10</price></product>
<product><title>456</title><price>11</price></product>
<product><title>789</title><price>12</price></product>
<product><title>a</title><price>14</price></product>
<product><title>b</title><price>15</price></product>
<product><title>c</title><price>16</price></product>
</products>
(over 100 records)

I need the output to have 3 columns, like this:
<table><tr><td>Product Title</td><td>Price</td><td>Product Title</td><td>Price</td><td>Product Title</td><td>Price</td></tr>
</table>

Any input would be greatly appreciated.

Thanks!

Quote:
quote:Originally posted by armmarti
 As I understand, you needn't to do any transformation; all you need is just to output a table. So, if this is true, look what can you do:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:param name="c" select="3"/>
    <xsl:param name="r" select="4"/>

    <xsl:template match="/">
        <xsl:call-template name="output-rows">
            <xsl:with-param name="columns" select="$c"/>
            <xsl:with-param name="rows" select="$r"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="output-rows">
        <xsl:param name="columns"/>
        <xsl:param name="rows"/>

        <xsl:choose>
                <xsl:when test="$rows > 0">
                    <tr>
                        <xsl:call-template name="output-columns">
                            <xsl:with-param name="columns" select="$columns"/>
                            <xsl:with-param name="rows" select="$rows"/>
                        </xsl:call-template>
                    </tr>            
                    <xsl:call-template name="output-rows">
                        <xsl:with-param name="columns" select="$columns"/>
                        <xsl:with-param name="rows" select="$rows - 1"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise/> 
        </xsl:choose>
    </xsl:template>

    <xsl:template name="output-columns">
        <xsl:param name="columns"/>
        <xsl:param name="rows"/>

        <xsl:choose>
                <xsl:when test="$columns > 0">
                    <td>
                        <xsl:element name="cell">
                            <xsl:value-of select="concat('[', $r - $rows + 1, ', ', $c - $columns + 1, ']')"/>
                        </xsl:element>
                    </td>            
                    <xsl:call-template name="output-columns">
                        <xsl:with-param name="columns" select="$columns - 1"/>
                        <xsl:with-param name="rows" select="$rows"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise/> 
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>
This stylesheet can be applied to any XML document (to itself, for example).
The stylesheet has 2 recursive templates; one to output rows and other to output columns. It's just simulating simple looping construct through recursive structure and nothing more. If you have any concrete question, let me know please.

Regards,
Armen
 
Old December 19th, 2003, 04:48 AM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via Yahoo to armmarti
Default

Hi,

Let's clarify what you want: the output you want has more than 3 columns... I guess you mistyped and really you want 2 columns (title and price). Please clarify the point to be able to help you.

Regards,
Armen
 
Old December 19th, 2003, 10:08 AM
Authorized User
 
Join Date: Dec 2003
Posts: 11
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to btado
Default

Oops, sorry for the typo.

The data makes the table too long when it is in only 2 columns (title, price) so I'd like to make the data go across 3 records per row and then down.

I would like to see a total of 6 columns (title, price, title, price, title, price) or 3 pairs as it scrolls through the records.

Thanks!!!!!

 
Old December 19th, 2003, 02:43 PM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via Yahoo to armmarti
Default

I've tried to deal with this as much generally as I could [ prior to my free time ;) ].

The stylesheet is general enough.

Any xml document can be rendered as soon as it has this structure (element types are irrelevant):
Code:
<rows>
  <row>
    <item1>...</item1>
    <item2>...</item2>
    ...
    <itemN>...</itemN>
  </row>
  ...
</rows>
Try to play with it. You can pass a parameter "n-big-cols" to the stylesheet to give the number of big-columns (3 in your example).

Enjoyed writing the stylesheet!
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:param name="n-big-cols" select="3"/>

    <xsl:variable name="all-items" select="/*/*"/>
    <xsl:variable name="n-items" select="count($all-items)"/>
    <xsl:variable name="n-rows" select="ceiling($n-items div $n-big-cols)"/>
    <xsl:variable name="n-fields" select="count($all-items[1]/*)"/>
    <xsl:variable name="first-col-color" select="'#cccccc'" />

    <xsl:template match="/">
        <html>
            <head>
                <title/>
            </head>
            <body>
                <table border="1" cellspacing="0">
                    <tbody>
                        <tr>
                            <xsl:call-template name="put-header"/>
                        </tr>
                        <xsl:call-template name="put-data"/>
                    </tbody>
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template name="put-header">
        <xsl:param name="idx" select="1"/>
        <xsl:if test="$idx &lt;= $n-big-cols">
            <xsl:for-each select="$all-items[1]/*">
                <th >
                    <xsl:if test="position() = 1">
                        <xsl:attribute name="bgcolor"><xsl:value-of select="$first-col-color"/></xsl:attribute>
                    </xsl:if>
                    <xsl:value-of select="local-name()"/>
                </th>
            </xsl:for-each>
            <xsl:call-template name="put-header">
                <xsl:with-param name="idx" select="$idx + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template name="put-data">
        <xsl:param name="idx" select="1"/>

        <xsl:if test="$idx &lt;= $n-rows">
            <tr>
                <xsl:call-template name="put-item">
                    <xsl:with-param name="r" select="$idx"/>
                    <xsl:with-param name="c" select="1"/>
                </xsl:call-template>
            </tr>
            <xsl:call-template name="put-data">
                <xsl:with-param name="idx" select="$idx + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template name="put-item">
        <xsl:param name="internal-col-idx" select="0"/>
        <xsl:param name="r"/>
        <xsl:param name="c"/>
        <xsl:if test="$c &lt;= $n-big-cols">
            <xsl:variable name="curr-el" select="$all-items[($c - 1) * $n-rows + $r]/*[$internal-col-idx + 1]"/>
            <xsl:choose>
                <xsl:when test="not($curr-el)">
                    <xsl:call-template name="fill-gap">
                        <xsl:with-param name="cnt" select="$n-fields"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <td>
                        <xsl:if test="not($curr-el/preceding-sibling::*)">
                            <xsl:attribute name="bgcolor"><xsl:value-of select="$first-col-color"/></xsl:attribute>
                        </xsl:if>
                        <xsl:value-of select="$curr-el"/>
                    </td>
                    <xsl:call-template name="put-item">
                        <xsl:with-param name="internal-col-idx" select="($internal-col-idx + 1) mod $n-fields"/>
                        <xsl:with-param name="r" select="$r"/>
                        <xsl:with-param name="c" select="$c + number(not($curr-el/following-sibling::*))"/>
                    </xsl:call-template>
                </xsl:otherwise> 
            </xsl:choose> 
        </xsl:if>
    </xsl:template>

    <xsl:template name="fill-gap">
        <xsl:param name="cnt"/>

        <xsl:if test="$cnt > 0">
            <td>
                <xsl:if test="$cnt = $n-fields">
                    <xsl:attribute name="bgcolor">
                        <xsl:value-of select="$first-col-color"/>
                    </xsl:attribute>
                </xsl:if>    
                #xA0;
            </td>
            <xsl:call-template name="fill-gap">
                <xsl:with-param name="cnt" select="$cnt - 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>
Regards,
Armen
 
Old December 19th, 2003, 02:47 PM
Friend of Wrox
 
Join Date: Jun 2003
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via Yahoo to armmarti
Default

Again all ampersands disappeared for character references...
Add the ampersand symbol before '#xA0;'
 
Old December 19th, 2003, 09:43 PM
Authorized User
 
Join Date: Dec 2003
Posts: 11
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to btado
Default

Wow!

You have out done yourself! Thank you immensely for all of your help.

I am wondering if you would know how to choose which columns of data that you want to display. I don't want to display all of the columns of data, just a few of them.

I could write a stylesheet to transform the xml to another xml file that only has the fields that I want...but could this stylesheet be adapted to be able to choose which fields you want to display?

Again, thanks for your help!!!!







Similar Threads
Thread Thread Starter Forum Replies Last Post
XSLT 1.0: Looping through nodes kwilliams XSLT 4 December 1st, 2008 06:21 PM
XSLT and tables surgeon XSLT 1 July 3rd, 2005 03:36 AM
XSLT Looping Logic - Very Urgent ujayaraman XSLT 2 March 3rd, 2005 10:42 AM
looping through 2 tables Hudson40 Access VBA 2 February 4th, 2005 01:12 PM
xslt looping richjo100 XSLT 6 September 23rd, 2004 11:20 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.