Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

XSL: divide XML data into three columns in a table.

Posted on 2006-05-19
5
Medium Priority
?
837 Views
Last Modified: 2008-02-07
I have this XML (it's in fact longer, but for the principle this will do). It's a list of names, which I want to display in a table, with in each cell all names that start with a certain letter. But I want the table to have three columns. Either I have a blackout, or it is really hard to do. It's easy to make an XSL that will create a seperate row for each letter. But how do I create three columns in a row?

<root>
    <letter value="A" count="1">
        <person id="22">
            <person_firstname>Andy</person_firstname>
        </person>
        <person id="8">
            <person_firstname>Adrian</person_firstname>
        </person>
    </letter>
    <letter value="B" count="2">
        <person id="29">
            <person_firstname>Benjamin</person_firstname>
        </person>
        <person id="38">
            <person_firstname>Bill</person_firstname>
        </person>
    </letter>
    <letter value="C" count="3">
        <person id="3">
            <person_firstname>Chris</person_firstname>
        </person>
    </letter>

    <letter value="D" count="4">
        <person id="3">
            <person_firstname>Dirk</person_firstname>
        </person>
    </letter>

    <letter value="E" count="5">
        <person id="3">
            <person_firstname>Evalyn</person_firstname>
        </person>
    </letter>

    <letter value="F" count="6">
        <person id="3">
            <person_firstname>Folkert</person_firstname>
        </person>
    </letter>
</root>


This is the HTML result I want to have.

<table>
    <tr>
        <td>
            Andy<br />
            Adrian<br />
        </td>
        <td>
            Benjamin<br />
            Bill<br />
        </td>
        <td>
            Chris<br />
        </td>
    </tr>
    <tr>
        <td>
            Dirk<br />
        </td>
        <td>
            Evalyn<br />
        </td>
        <td>
            Folkert<br />
        </td>
    </tr>
</table>    
   

0
Comment
Question by:sybe
  • 3
  • 2
5 Comments
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 1500 total points
ID: 16716887
Hi sybe,

This is not the nicest solution,
but it is the easiest

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <xsl:for-each select="//person[(count(preceding::person) + 1) mod 3 = 1]">
            <tr>
                <td><xsl:value-of select="person_firstname"/></td>
                <td><xsl:value-of select="following::person[1]/person_firstname"/></td>
                <td><xsl:value-of select="following::person[2]/person_firstname"/></td>
            </tr>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>


Cheers!
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 16717026
sybe,

using recursive processing with call-template
you can make this more generic, so that you have more flexibility in the number of columns

but for now, this should do

cheers

Geert
0
 
LVL 28

Author Comment

by:sybe
ID: 16717048
Thanks.

I am interested in the recursive solution. That solution might also give the possibility to make the number of columns a parameter, and that's a lot more flexible.
0
 
LVL 28

Author Comment

by:sybe
ID: 16717241
Ok, I got it working. the "mod" thing was what I needed, did not know it could be used is XSL.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:user="urn:my-namespace" version="1.0">
<xsl:param name="columns" select="3"/>
<xsl:template match="/">

<html>
<body>

<table border="0" cellpadding="5" cellspacing="1" width="100%">
    <xsl:for-each select="//letter[number(@count) mod number($columns) = 1]">
        <xsl:variable name="currentCount" select="number(@count)"/>
        <tr>
            <xsl:for-each select="//letter[number(@count) &gt;=$currentCount and number(@count) &lt; ($currentCount+number($columns))]">
                <xsl:variable name="currentLetter" select="@value"/>
                <xsl:call-template name="lettercell">
                    <xsl:with-param name="currentLetter" select="$currentLetter"/>
                </xsl:call-template>
            </xsl:for-each>
        </tr>
    </xsl:for-each>
</table>

</body>
</html>
</xsl:template>


<xsl:template name="lettercell">
    <xsl:param name="currentLetter"/>
    <td width="33%" valign="top">
        <table width="100%">
            <tr>
                <td width="100%"><xsl:value-of select="@value"/></td>
            </tr>
            <tr>
                <td>
                    <xsl:for-each select="//letter[@value=$currentLetter]/person">
                        <xsl:value-of select="person_firstname"/>&#160;<br />
                    </xsl:for-each>
                </td>
            </tr>
        </table>
    </td>
</xsl:template>

</xsl:stylesheet>



0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 16717663
sybe,
> I am interested in the recursive solution.

that would be it
(works for NoC > 1)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:param name="NoC">3</xsl:param>
    <xsl:template match="/">
        <xsl:for-each select="//person[(count(preceding::person) + 1) mod $NoC = 1]">
            <tr>
                <xsl:call-template name="createCells">
                    <xsl:with-param name="currNode" select="."/>
                    <xsl:with-param name="remainingCells" select="$NoC"/>
                </xsl:call-template>
            </tr>
        </xsl:for-each>
    </xsl:template>
    <xsl:template name="createCells">
        <xsl:param name="remainingCells"/>
        <xsl:param name="currNode"/>
        <td><xsl:value-of select="$currNode/person_firstname"/></td>
        <xsl:if test="$currNode/following::person and $remainingCells &gt; 1">
            <xsl:call-template name="createCells">
                <xsl:with-param name="currNode" select="$currNode/following::person[1]"/>
                <xsl:with-param name="remainingCells" select="$remainingCells - 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The Client Need Led Us to RSS I recently had an investment company ask me how they might notify their constituents about their newsworthy publications.  Probably you would think "Facebook" or "Twitter" but this is an interesting client.  Their cons…
Create a Windows 10 custom Image with custom task bar and custom start menu using XML for deployment.
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses
Course of the Month15 days, 8 hours left to enroll

575 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question