Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
| Search | Today's Posts | Mark Forums Read
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
  #1 (permalink)  
Old October 18th, 2006, 11:18 AM
knc knc is offline
Registered User
 
Join Date: Oct 2006
Location: , , USA.
Posts: 1
Thanks: 0
Thanked 0 Times in 0 Posts
Default Hierarchical HTML unordered lists from any XML

Hi. I am a newbie at XSLT. I have done some other programming, but I have to admit, I am not very good. I have Kay's book XSLT 2.0 and am reading through some examples. My code ultimately will go into PHP code, which, I think, uses Sablotron, v 1.0. I am currently using a testing application called TextXSLT on Mac OS X.

My current project is creating an HTML formatted unordered list ([list]) from any XML file. My current pseudo-code is as follows:

"For-each" through all of the elements. Create the necessary[list] tag. Determine the depth of each of the elements. Then, compare that depth to the previous element's depth. If current element - previous element = 0, then create another <li>--i.e., the depth is the same. If current element - previous element = 1, then we have increased in depth and we need another[list] and <li>. Conversely, if current element - previous element < 0, take that absolute difference and create that number of </ul> closing tags.

(I know there will need to be other closing tags and other tests, but this is a start. If there is a better/easier way of doing it, please stop me here.)

The first stumbling block I am working on now is that of getting the depths of the previous element. Here is my code:
Code:
<?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='no'/>
<xsl:template match="/">

<xsl:param name="prevdepth" select="number"/>

<xsl:for-each select="//*">
<xsl:value-of select="local-name()"/>: <xsl:apply-templates select="current()/text()"/>
(depths: <xsl:value-of select="count(ancestor-or-self::*)"/>-<xsl:value-of select="$prevdepth"/>)
<xsl:call-template name="ulli"/>
</xsl:for-each>
</xsl:template>

<xsl:template name="ulli">
<xsl:param name="prevdepth" select="count(ancestor-or-self::*)"/>
</xsl:template>

</xsl:stylesheet>
Because I need the relative depth, I am first calling a template and storing the current depth as a parameter there. Then, I retrieve that parameter value on the next for-each iteration. Currently, I am getting an empty string for all of the difference values. I've tried various things, one of which gets me "0" instead of nothing...though I can't remember what the code was.

Thanks in advance for any help!
  #2 (permalink)  
Old October 18th, 2006, 11:40 AM
Friend of Wrox
Points: 1,676, Level: 16
Points: 1,676, Level: 16 Points: 1,676, Level: 16 Points: 1,676, Level: 16
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2006
Location: , , .
Posts: 430
Thanks: 28
Thanked 5 Times in 5 Posts
Send a message via Yahoo to bonekrusher
Default

In XSLT 2.0 (book) look in the index for "list". He has a great example on how to do what I think you are trying to do.

  #3 (permalink)  
Old October 18th, 2006, 11:43 AM
mhkay's Avatar
Wrox Author
Points: 18,487, Level: 59
Points: 18,487, Level: 59 Points: 18,487, Level: 59 Points: 18,487, Level: 59
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

You've started with a very procedural description of an algorithm:

>"For-each" through all of the elements. Create the necessary[list] tag. Determine the depth of each of the elements. Then, compare that depth to the previous element's depth. If current element - previous element = 0, then create another <li>--

This isn't usually a good starting point for XSLT coding. It's much better to try to describe the output as a function of the input: "for every element in the input there must be a[list] in the output and for each of its children there must be a corresponding <li>..."

I'm having trouble reverse engineering your requirements from your procedural solution. But you seem to be doing a very direct translation of one hierarchy into another, and it should be possible to describe this entirely using template rules. Try to describe it in these terms: "for an element with children, I want a[list] in the output with each of its children wrapped in an <li>". For an element without children, I want...

Then you can translate this directly into template rules:

<xsl:template match="*[*]"> [list]
  <xsl:for-each select="*">
    <li><xsl:apply-templates select="."/></li>

<xsl:template match="*[not(*)]">
  <xsl:value-of select="."/>
</xsl:template>

and so on.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference


Similar Threads
Thread Thread Starter Forum Replies Last Post
flat XML to hierarchical XML eduijs XSLT 1 April 28th, 2006 05:43 AM
translating a flat xml to a hierarchical xml stevea XSLT 4 June 13th, 2005 05:55 PM
unordered elements in complex type mandabear XML 0 September 3rd, 2004 11:08 AM
Word Bulleted Paragraphs to HTML Unordered Lists schurli XSLT 10 August 21st, 2003 01:40 AM
XML non-hierarchical menus rotnative Classic ASP XML 0 June 10th, 2003 02:58 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.