0

I'm struggling to create a list to be displayed on the condition of the parent node ('folder') with attribute 'folded' set to either 'yes' or 'no'. The result shall display the first two levels of the list only and not the third level as below.

  • 1st. Level: display
  • 2nd. Level: display
  • 3rd. Level: NO display

The idea is to check the 'folder'-attribute <folder folded="yes"> with <xsl:if test="not(parent::yes)">. That should qualify for the 3rd. Level to NOT being displayed, but somehow it doesn't do what I want it to do. I probably use the wrong construct and/or syntax. Assistance is highly appreciated, thanks.

The XML structure with some content:

<xbel>
    <folder folded="yes">
        <level>1</level>
        <title>bookmarks</title>
        <desc>my bookmarks</desc>
        <folder folded="no">
            <level>2</level>
            <title>Android</title>
            <desc>my Android</desc>
            <bookmark href="http://www.phonesreview.co.uk/">
                <title>HTC Sync 3.0.5422 Update: Aria, Desire, Hero, Legend</title>
                <desc>The new HTC Sync 3.0.5422 update will be most welcome...</desc>
            </bookmark>
            <folder folded="no">
                <level>3</level>
                <title>Apps</title>
                <desc>Android Apps</desc>
                <bookmark href="http://www.androidzoom.com/">
                    <title>Android Communication Apps</title>
                    <desc>Download Communication Apps for Android.</desc>
                </bookmark>
                <bookmark href="http://www.htc.com/">
                    <title>HTC - Android</title>
                    <desc>Apps for HTC-Android.</desc>
                </bookmark>
            </folder>
        </folder>
    </folder>
</xbel>

The XSLT:

 <!--creates a nested list of elements named 'folder'-->
<xsl:template match="folder" mode="linklist">
    <li>
        <xsl:if test="folder/level = 2">
                Level:<xsl:value-of select="level"/> / 
                Title:<xsl:value-of select="title"/> / 
                Desc:<xsl:value-of select="desc"/>
        <ul>
            <xsl:apply-templates mode="linklist" />
        </ul>
        </xsl:if>
    </li>
</xsl:template>

<xsl:template match="bookmark" mode="linklist">
    <li>  <!-- this bookmark is just another item in the list of bookmarks -->
        <!-- the title -->
            <a rel="nofollow" href="{@href}"><xsl:value-of select="title"/></a>
        <!-- the description -->
        <xsl:if test="desc">
            <span class="bookmarkDesc">
                <xsl:value-of select="desc"/>
            </span>
        </xsl:if>
    </li>
</xsl:template>

The Stylesheet HTML

<body>

<ul>
    <xsl:apply-templates mode="linklist" />
</ul>

</body>

The generated output (levels:1-3)

Level:1 / Title:bookmarks / Desc:my bookmarks
        Level:2 / Title:Android / Desc:my Android
            HTC Sync 3.0.5422 Update: Aria, Desire, Hero, Legend ...
            Level:3 / Title:Apps / Desc:Android Apps
                Android Communication AppsDownload Communication Apps for Android.
                HTC - AndroidApps for HTC-Android.

The anticipated output: (levels: 1-2)

Level:1 / Title:bookmarks / Desc:my bookmarks
        Level:2 / Title:Android / Desc:my Android
            HTC Sync 3.0.5422 Update: Aria, Desire, Hero, Legend ...

I tried this template, but that outputs the last two nodes, I need the two first nodes.

<xsl:template match="folder[parent::folder/@folded = 'yes']" mode="linklist">
snahl
  • 497
  • 2
  • 10
  • 25

1 Answers1

1

The simplest possible change you could make to prevent processing of unfolded folder elements is to add an empty template that swallows them (i.e. produces no output):

<xsl:template match="folder[@folded='no']" mode="linklist"/>

All folder elements not having a folded attribute equal to no will be processed using your existing template; those that do will be captured by this new one.

If instead you want to process each folder element having either its own folded attribute equal to yes or that of its parent (as in the updated XML example), then use the following template:

<xsl:template match="folder[@folded='yes' or ../@folded='yes']" mode="linklist">
    <!-- body elided -->
</xsl:template>

You'll probably also want to include an empty template for hiding all other folder elements:

<xsl:template match="folder" mode="linklist" />
Wayne
  • 59,728
  • 15
  • 131
  • 126
  • thanks: Note that the 2nd. node to be displayed has an attribute `@folded='no'` and its parent only has the attribute `@folded='yes'` – snahl Aug 22 '11 at 14:34
  • @snahl - It didn't at the time I answered. You have edited. I can update my answer once I understand these changed requirements. You want to output only those folders whose `folded` attribute is `yes` or whose parent `folder` has a `folded` attribute equal to `yes'. Is that right? – Wayne Aug 22 '11 at 14:51
  • Correct, I had edit the XML after reading your reply. The aim is to output only those folders whose `parent folder` has a `folded attribute equal to 'yes`. – snahl Aug 22 '11 at 15:45
  • Something like this: `` or like this `` seems to take me onto the right path to the result. What do you think? – snahl Aug 22 '11 at 15:47
  • Well, you also need to output the first `folder`, which does not have a parent `folder`, so doesn't meet the requirement you've given. I would just explicitly match the folders you want: ``. And then include an empty template for hiding everything else: ``. Including a match for folders whose `folded` attribute equals `yes` doesn't cost you anything, because to ever get to a folder whose parent has that attribute, you'd have to process such a folder first. Make sense? – Wayne Aug 22 '11 at 16:18
  • Yes, makes sense and works as well. Both of suggestions also work by applying the 'double negation (not and no)'. eg: `` the first folder does get listed. Problem solved, thanks. – snahl Aug 22 '11 at 16:32
  • Great. I'm going to edit my answer to reflect our conversation. – Wayne Aug 22 '11 at 17:04