Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > XML > xslt to HTML Transform question

Reply
Thread Tools

xslt to HTML Transform question

 
 
Adam dR.
Guest
Posts: n/a
 
      11-25-2006
I have an xml file similar to:
<menu>
<menuitem name="home" show="false"/>
<menuitem name="about" show="true"/>
<menuitem name="links" show="true"/>
<menuitem name="games" show="true"/>
<menuitem name="learn" show="true"/>
<menuitem name="order" show="true"/>
<menuitem name="contact" show="true"/>
<menuitem name="support" show="false"/>
<menuitem name="feedback" show="true"/>
....
</menu>

What I am trying to achieve is a table that takes every four menuitems
that are show="true" and put them in a table row and then put each
menuitem is a <td>..

Desired output:
<table>
<tr>
<td>about</td>
<td>links</td>
<td>games</td>
<td>learn</td>
</tr>
<tr>
<td>order</td>
<td>contact</td>
<td>feedback</td>
</tr>
</table>

I cannot figure out how to loop four and place them in a <tr> tag

What I have tried:
<xsl:template match="/">
<table>
<xsl:apply-templates select="menu"/>
</table>
</xsl:template>

<xsl:template match="menu">
<xsl:for-each select="menuitem[@show='true']">

<xsl:if test="position() mod 4 = 1">
<xsl:text >&lt;tr&gt;</xsl:text>
</xsl:if>

<td><xsl:value-of select="@name"/></td>

<xsl:if test="position() mod 4 = 0">
<xsl:text>&lt;tr&gt;</xsl:text>
</xsl:if>

</xsl:for-each>
</xsl:template>

There are a couple problems with this, 1. the position is still the
position of all menuitems true or false so I am not guaranteed 4 items
per row. 2. and most of all if actually right "<tr>" rather then
placing the <tr> tag in the html doc.

Any help would be great!

~Adam dR.

 
Reply With Quote
 
 
 
 
xmlator@gmail.com
Guest
Posts: n/a
 
      11-26-2006

Michael Kay's XSLT 2nd Edition has a decent explanation of
this class of problem, which can be found by looking in the index
for "tail recursion".

> There are a couple problems with this, 1. the position is still the
> position of all menuitems true or false


Couldn't quite grok that statement. Seems to me position()
would reflect the position of the nodelist formed by the
for-each select clause. xsltproc seemed to agree with my
assumption. Maybe I've missed something here.

> per row. 2. and most of all if actually right "<tr>" rather then
> placing the <tr> tag in the html doc.


That gets you to the nut: using recursion instead of iteration.
Here's one possible solution:

<?xml version="1.0"?>
<xsl:stylesheet
xmlnssl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
version="1.0"
>

<xslutput method="html" indent="yes"/>

<xsl:template name="EmitRows">
<xslaram name="MenuItemList" />

<xsl:if test="count($MenuItemList) != 0">
<tr>
<xsl:for-each select="$MenuItemList[position() &lt; 5]">
<td><xsl:value-of select="@name" /></td>
</xsl:for-each>
</tr>
<xsl:call-template name="EmitRows">
<xsl:with-param name="MenuItemList"
select="$MenuItemList[position() &gt; 4]" />
</xsl:call-template>
</xsl:if>

</xsl:template>

<xsl:template match="/">
<table>
<xsl:apply-templates select="menu"/>
</table>
</xsl:template>

<xsl:template match="menu">
<xsl:call-template name="EmitRows">
<xsl:with-param name="MenuItemList"
select="./menuitem[@show='true']" />
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>

xsltproc applies this XSLT file to your example XML data to produce:

<table>
<tr>
<td>about</td>
<td>links</td>
<td>games</td>
<td>learn</td>
</tr>
<tr>
<td>order</td>
<td>contact</td>
<td>feedback</td>
</tr>
</table>

Basic technique is to write a callable template that just returns
if the list is empty. If it's not empty, it does something useful with
one or more items at the front of the list, then passes all the other
items to itself recursively.

Hope this helps,
Ron Burk
www.xmlator.com

 
Reply With Quote
 
 
 
 
Dimitre Novatchev
Guest
Posts: n/a
 
      11-26-2006
> Michael Kay's XSLT 2nd Edition has a decent explanation of
> this class of problem, which can be found by looking in the index
> for "tail recursion".


Not all XSLT processors handle tail recursion gracefully. It is safer to use
another general method that just shortens dramatically the maximum size of
the call-stack needed -- DVC (Divide and Conquer). For example, to process
recursively a list of 1000000 (1M) items, the DVC method will use a stack
with maximum depth ~ 19 (log2(N) ).

One can read more about implementing DVC in XSLT here:

http://www.topxml.com/code/default.a...20020107050418


Or I'd recommend that one uses some of the most generic functions for
recursive processing, such as foldl(), implemented in the FXSL library. It
comes with most functions already implemented DVC, so one will not have to
do anything in addition but just use the functions.

Find more about FXSL here:

http://fxsl.sf.net (especially read the latest paper for the "Extreme
Markup Languages 2007" conference).


Cheers,
Dimitre Novatchev


<(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.com...
>
> Michael Kay's XSLT 2nd Edition has a decent explanation of
> this class of problem, which can be found by looking in the index
> for "tail recursion".
>
>> There are a couple problems with this, 1. the position is still the
>> position of all menuitems true or false

>
> Couldn't quite grok that statement. Seems to me position()
> would reflect the position of the nodelist formed by the
> for-each select clause. xsltproc seemed to agree with my
> assumption. Maybe I've missed something here.
>
>> per row. 2. and most of all if actually right "<tr>" rather then
>> placing the <tr> tag in the html doc.

>
> That gets you to the nut: using recursion instead of iteration.
> Here's one possible solution:
>
> <?xml version="1.0"?>
> <xsl:stylesheet
> xmlnssl="http://www.w3.org/1999/XSL/Transform"
> xmlns:exsl="http://exslt.org/common"
> extension-element-prefixes="exsl"
> version="1.0"
>>

> <xslutput method="html" indent="yes"/>
>
> <xsl:template name="EmitRows">
> <xslaram name="MenuItemList" />
>
> <xsl:if test="count($MenuItemList) != 0">
> <tr>
> <xsl:for-each select="$MenuItemList[position() &lt; 5]">
> <td><xsl:value-of select="@name" /></td>
> </xsl:for-each>
> </tr>
> <xsl:call-template name="EmitRows">
> <xsl:with-param name="MenuItemList"
> select="$MenuItemList[position() &gt; 4]" />
> </xsl:call-template>
> </xsl:if>
>
> </xsl:template>
>
> <xsl:template match="/">
> <table>
> <xsl:apply-templates select="menu"/>
> </table>
> </xsl:template>
>
> <xsl:template match="menu">
> <xsl:call-template name="EmitRows">
> <xsl:with-param name="MenuItemList"
> select="./menuitem[@show='true']" />
> </xsl:call-template>
> </xsl:template>
> </xsl:stylesheet>
>
> xsltproc applies this XSLT file to your example XML data to produce:
>
> <table>
> <tr>
> <td>about</td>
> <td>links</td>
> <td>games</td>
> <td>learn</td>
> </tr>
> <tr>
> <td>order</td>
> <td>contact</td>
> <td>feedback</td>
> </tr>
> </table>
>
> Basic technique is to write a callable template that just returns
> if the list is empty. If it's not empty, it does something useful with
> one or more items at the front of the list, then passes all the other
> items to itself recursively.
>
> Hope this helps,
> Ron Burk
> www.xmlator.com
>



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Dynamically Loading an XSLT Transform Inside an HTML DIV? pbd22 XML 0 06-29-2007 09:03 PM
Transform XML string using XSLT file Isambella via DotNetMonster.com ASP .Net 4 08-02-2005 07:19 AM
blocking I/O with javax.xml.parsers.DocumentBuilder.parse() and javax.xml.transform.Transformer.transform() jazzdman@gmail.com Java 1 03-27-2005 06:56 AM
Using XSLT parameters in a browser transform David XML 1 04-03-2004 02:00 PM
Transform XML using XSLT based on element position Igor XML 1 07-20-2003 08:16 PM



Advertisments