Solved

xml table with two columns

Posted on 2003-11-09
16
308 Views
Last Modified: 2012-06-22

i have the data in following format

<table_node>

<website>
<name>yahoo</name>
<url>www.yahoo.com</url>
</website>

<website>
<name>google</name>
<url>www.google.com</url>
</website>

<website>
<name>altavista</name>
<url>www.altavista.com</url>
</website>

<website>
<name>alltheweb</name>
<url>www.alltheweb.com</url>
</website>


<website>
<name>taeoma</name>
<url>www.taeoma.com</url>
</website>

</table_node>

i am trying to write xsl to transform the data in tabular format. i am able to do this using one column but i need
to arrange in 2 columns  so that i can create table of hyperlinks.

any way to do this?
0
Comment
Question by:sarika1977
  • 7
  • 5
  • 2
  • +1
16 Comments
 

Expert Comment

by:rishisk
ID: 9711895
Can you paste your xsl code here.
0
 
LVL 6

Expert Comment

by:metalmickey
ID: 9713236
Heres a xsl that will build 2 columns

<?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:template match="/">
    <html>
      <title/>
      <head/>
      <body>
        <table>
          <tr>
            <th>Name</th>
            <th>URL</th>
          </tr>
          <xsl:apply-templates/>
        </table>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="website">
    <tr>
      <xsl:apply-templates/>
    </tr>
  </xsl:template>
  <xsl:template match="name">
    <td align="left">
      <xsl:apply-templates/>
    </td>
  </xsl:template>
  <xsl:template match="url">
    <td align="left">
 <!--     <a><xsl:attribute name="href"><xsl:value-of select="."/></xsl:attribute>   -->
        <xsl:apply-templates/>
<!--      </a>   -->
    </td>
  </xsl:template>
</xsl:stylesheet>


If you want the URL's to become links, just remove the comments from around the

<a> <!-- in the xsl  --> and the </a>


MM
0
 

Author Comment

by:sarika1977
ID: 9715452
thanks mm !
but it doesn't solve my problem.

it arranges data like
 
yahoo
google
altavista
alltheweb
taeoma

etc.

I'm interested in arranging data with hyperlinks like

yahoo            alltheweb
google            taeoma
altavista        --

0
 

Expert Comment

by:rishisk
ID: 9716834
Somebody had a similar requirement. Check this out.

http://www.codeguru.com/forum/showthread.php?threadid=262467
0
 

Author Comment

by:sarika1977
ID: 9719943
rishisk

yep, the page has similar requirement but it doesn't arrange in the sequence i am looking for.

say
1
2
3
4
5
6

i need to arrange it in
1    4
2    5
3    6

order.

i am newbie and do not know how to achieve this.
0
 
LVL 26

Accepted Solution

by:
rdcpro earned 200 total points
ID: 9724406
That's actually fairly easy, but a tough one for a newbie! ;^) This will do it:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:variable name="vMidPoint" select="ceiling(count(table_node/website) div 2)"/>
    <xsl:template match="table_node">
        <table border="1" cellpadding="5" cellspacing="0">
            <xsl:apply-templates select="website[position() &lt;= $vMidPoint]"/>
        </table>
    </xsl:template>
    <xsl:template match="website">
        <tr>
            <td><a href="{url}"><xsl:value-of select="name"/></a></td>
            <td>
                <xsl:if test="following-sibling::website[$vMidPoint]">
                    <a href="{following-sibling::website[$vMidPoint]/url}"><xsl:value-of select="following-sibling::website[$vMidPoint]/name"/></a>
                </xsl:if>
            </td>        
        </tr>
    </xsl:template>

</xsl:stylesheet>



and produces this HTML:

<table border="1" cellpadding="5" cellspacing="0">
    <tr>
        <td>
            <a href="www.yahoo.com">yahoo</a>
        </td>
        <td>
            <a href="www.alltheweb.com">alltheweb</a>
        </td>
    </tr>
    <tr>
        <td>
            <a href="www.google.com">google</a>
        </td>
        <td>
            <a href="www.taeoma.com">taeoma</a>
        </td>
    </tr>
    <tr>
        <td>
            <a href="www.altavista.com">altavista</a>
        </td>
        <td>
        </td>
    </tr>
</table>


Regards,
Mike Sharp

http://dev.rdcpro.com


0
 
LVL 26

Expert Comment

by:rdcpro
ID: 9724433
Actually, to add the "http://" to the link modify this line like:

          <td><a href="http://{url}"><xsl:value-of select="name"/></a></td>

and do the same for the right hand column:

<a href="http://{following-sibling::website[$vMidPoint]/url}"><xsl:value-of select="following-sibling::website[$vMidPoint]/name"/></a>

Regards,
Mike Sharp
0
 
LVL 6

Expert Comment

by:metalmickey
ID: 9725004
Hi Mike

can you anotate the template for me so i can see whats happening.

Thanks

MM
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 
LVL 26

Expert Comment

by:rdcpro
ID: 9725295
Sure, but it's not all that obscure when you get the core idea.  First, I find the midpoint.  If there are an odd number of items, then I want the "extra" item in the first group.  So I use the ceiling() XPath function:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:variable name="vMidPoint" select="ceiling(count(table_node/website) div 2)"/>

That way, $vMidPoint will always tell me what the position of the first item in the second column is.  To build my table, I want a nodeset which only includes those items that are less than or equal to the midpoint.  In the example, it's the first three items.  So I apply-templates for <website> where the position is less than or equal to $vMidPoint (which is 3, in the example).


    <xsl:template match="table_node">
        <table border="1" cellpadding="5" cellspacing="0">
            <xsl:apply-templates select="website[position() &lt;= $vMidPoint]"/>
        </table>
    </xsl:template>


The next template is fairly simple, but contains the key to the process. The first TD is easy...just the current node, right?

    <xsl:template match="website">
        <tr>
            <td><a href="{url}"><xsl:value-of select="name"/></a></td>

The next TD is the tricky one.  The following-sibling axis counts from the current node forward in *document* order.  It is important to realize that it works on the original nodeset of the original XML, not the set of nodes I'm working with in my apply-templates!  So what I want is the 3rd node after the current node, whatever it is, because my midpoint is 3.  So if I'm processing the very first node, in the 2nd TD I want the *fourth* node.  When I process the 2nd node, I want the 5th node, and so on.  I start off with an xsl:if, because I don't want to put a blank <a> tag in the output unless there is a node to process at that point.  If I was working on the first <website> node, it would be similar to this XPath expression (assuming it were legal):

"//website[position() = (current()/position() + 3)]"

but since you can't use current()/position() in XPath, you have the following-sibling axis, which means essentially, "starting from the current position..."

            <td>
                <xsl:if test="following-sibling::website[$vMidPoint]">
                    <a href="{following-sibling::website[$vMidPoint]/url}"><xsl:value-of select="following-sibling::website[$vMidPoint]/name"/></a>
                </xsl:if>
            </td>        
        </tr>
    </xsl:template>

</xsl:stylesheet>

And that's all there is to it!

Regards,
Mike Sharp
0
 
LVL 26

Expert Comment

by:rdcpro
ID: 9725319
I should have said:

"That way, $vMidPoint will always tell me the position immediately before the first item in the second column."

meaning, if there are seven items, $vMidPoint is 4, and the first item in the second column will be item #5

Regards,
Mike Sharp
0
 

Author Comment

by:sarika1977
ID: 9725518
thank you very much mike, it works great  but gives another problem when i embedd inside the another 'template match' statement.

can't I use nested 'template match' ?
0
 
LVL 26

Expert Comment

by:rdcpro
ID: 9725953
No you can't.  xsl:template must be an immediate child of <xsl:stylesheet> (or xsl:transform, if you use that one)

Just extract the logic from my example, and implement it in your XSLT, or post your XSLT.

Regards,
Mike Sharp
0
 

Author Comment

by:sarika1977
ID: 9731727
i tried something like the following. it creates table with 2 columns  inside xsl:template but doesn't order properly.

<tr>
<xsl:for-each select="table_node/website">
<xsl:variable name="vCurPosition" select="position()"/>
<xsl:choose>
<xsl:when test="$vCurPosition mod 2 = 0">
<td><xsl:value-of select="name"/>

</td>
&lt;/tr> &lt;tr>
</xsl:when>
<xsl:otherwise>
<td> <xsl:value-of select="name"/>
</td>
</xsl:otherwise>
</xsl:choose>

</xsl:for-each>

</tr>
0
 
LVL 26

Expert Comment

by:rdcpro
ID: 9732498
Any time you find yourself doing this:

</td>
&lt;/tr> &lt;tr>

you're doing XSLT wrong.  There is never a case where you have to resort to this type of situation in XSLT.  In fact, your output will actually be:

</td>
&lt;/tr> &lt;tr>

and not:

</td>
</tr> <tr>

I can't stress this enough.  Do not resort to entities in the XSLT, or other tricks like that simply in order to get around the well-formedness constraints.  I have a number of examples how to build tables like this on my site.  For example:

http://dev.rdcpro.com/Members/rdcpro/snippets/xpathgrouping/
and
http://dev.rdcpro.com/Members/rdcpro/snippets/xpathgrouping2/



The modulo approach is used to create tables that are ordered like:

1    2
3    4
5    6

not in the newspaper style you said you're trying to achieve:

1    4
2    5
3    6

Perhaps you could post your complete XSLT?  It's very difficult to figure out what you're trying to do from a snippet.

Regards,
Mike Sharp
0
 

Author Comment

by:sarika1977
ID: 9733232
thanks you very much mike for the tip. i guess i need to work a lot for
learning xsl.

what i'm trying to achive is:

i have a list

1
2
3
4
5
6
7

i am trying to put it in a table like

1  5
2  6
3  7
4

i need to embedd this code inside the existing xsl which already has
'xsl:template match' statement. i don't want to change the existing functionality and achive the desired effect.

thanks
0
 
LVL 26

Expert Comment

by:rdcpro
ID: 9733306
My original code does just that...read the annotated version I posted for MetalMickey, it should explain how this is done.  You'll have to integrate my approach into your XSLT, but without seeing your XSLT, I can't tell you specifically how it would be done.  But you won't use the mod operator for it.  You'll add a global variable that identifies the mid point, then apply templates (or use a for-each) on the nodes whose position is up to and including the midpoint.  This builds the rows, and the first TD cell.  The second TD cell is built using the node from the original nodes that is at the current node's position plus the midpoint.

Regards,
Mike Sharp
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

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…
Many times as a report developer I've been asked to display normalized data such as three rows with values Jack, Joe, and Bob as a single comma-separated string such as 'Jack, Joe, Bob', and vice versa.  Here's how to do it. 
This video discusses moving either the default database or any database to a new volume.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

746 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now