Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

xml table with two columns

Posted on 2003-11-09
16
312 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
Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

 

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
 
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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Fetch XML Unions? 3 681
Unable to resolve XML http request 4 99
AL3 Files 4 39
split XML field into many fields from MS Access 21 44
Introduction In my previous article (http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/SSIS/A_9150-Loading-XML-Using-SSIS.html) I showed you how the XML Source component can be used to load XML files into a SQL Server database, us…
The Confluence of Individual Knowledge and the Collective Intelligence At this writing (summer 2013) the term API (http://dictionary.reference.com/browse/API?s=t) has made its way into the popular lexicon of the English language.  A few years ago, …
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

860 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