xml table with two columns


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?
sarika1977Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

rishiskCommented:
Can you paste your xsl code here.
0
metalmickeyCommented:
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
sarika1977Author Commented:
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
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

rishiskCommented:
Somebody had a similar requirement. Check this out.

http://www.codeguru.com/forum/showthread.php?threadid=262467
0
sarika1977Author Commented:
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
rdcproCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
rdcproCommented:
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
metalmickeyCommented:
Hi Mike

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

Thanks

MM
0
rdcproCommented:
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
rdcproCommented:
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
sarika1977Author Commented:
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
rdcproCommented:
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
sarika1977Author Commented:
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
rdcproCommented:
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
sarika1977Author Commented:
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
rdcproCommented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.