Tree menu and filtering entries by category
This is an open discussion with 9 replies, filed under XSLT.
Search
Hi gferreira. I suggest you post your XML here, too. You may already know this, of course, but you can see the XML by appending ?debug=xml
to the end of the page URL when you are logged in.
Hi David, thank you for your reply.
I can see the full source data in the XML with ?debug
, but I don't know how to “call” it into the menu with XSLT.
The XML of the sections looks like this:
<chapters> <section handle="chapters">Chapters</section> <entry> <title handle="chapter-1">Chapter 1</title> </entry> <entry> <title handle="chapter-2">Chapter 2</title> </entry> </chapters> <docs> <section handle="docs">Docs</section> <entry> <title handle="a-doc-page">A Doc Page</title> <body mode="formatted">...</body> <chapter> <item handle="chapter-1">Chapter 1</item> </chapter> </entry> <entry> <title handle="another-doc-page">Another Doc Page</title> <body mode="formatted">...</body> <chapter> <item handle="chapter-2">Chapter 2</item> </chapter> </entry> </docs>
I'll keep on trying, and will post results here if I can get it to work.
@gferreira
First of all I suggest using matched templates
when coding instead of for-each. It's kind-of good practice.
<xsl:template name="nav-docs"> <ul class='tree'> <xsl:apply-templates select="/data/chapters/entry"> </ul> </xsl:template> <xsl:template match="chapters/entry"> <li> <span> <xsl:value-of select="title"/> </span> <ul> <xsl:apply-templates select="/data/docs/entry[ chapter/item/@id = current()/@id ]"> </ul> </li> </xsl:template> <xsl:template match="docs/entry"> <li> <a href="...">...</a> </li> </xsl:template>
This
<xsl:apply-templates select="/data/docs/entry[ chapter/item/@id = current/@id ]">
matches each doc entry when it's chapter id is the same as current chapter id.
@vladG: Many thanks for your reply, this is exactly what I was looking for.
(I am coming from a Python background, so I am used to think in terms of for-each
s. Still trying to wrap my head around the XSLT way of doing things – your example was very helpful.)
I got it to work with a few changes:
<xsl:template name="nav-docs"> <ul class='tree'> <xsl:apply-templates select="/data/chapters/entry" /> </ul> </xsl:template> <xsl:template match="chapters/entry"> <li> <span> <xsl:value-of select="title"/> </span> <ul> <xsl:apply-templates select="/data/docs/entry[ chapter/item/@handle = current()/title/@handle ]" /> </ul> </li> </xsl:template> <xsl:template match="docs/entry"> <li> <a href="#"> <xsl:value-of select="title"/> </a> </li> </xsl:template>
So, the matching was not between @id
s, but between chapter/@handle
(doc page) and title/@handle
(chapter).
Cheers!
I had forgotten to add the URL to each doc page, so here's an update:
<xsl:template match="docs/entry"> <li> <a> <xsl:attribute name="href"> <xsl:value-of select="concat($root, '/docs/', title/@handle)" /> </xsl:attribute> <xsl:value-of select="title"/> </a> </li> </xsl:template>
Is there a more elegant way of doing the concat()
part? (For example, without hard-wiring the docs
section?)
Next:
- make the menu tree stay open for the current chapter when switching pages
- add
next
andprevious
links for page navigation
Is there a more elegant way of doing the concat() part? (For example, without hard-wiring the docs section?)
Well, not really. That is the handle of your Docs Page
in the end. If you need to rename the handle, you'll make a global search & replace in your stylesheets (.xsl files).
Perhaps you would use this to look prettier:
<a href="{$root}/docs/{title/@handle}"> <xsl:value-of select="title"/> </a>
Thanks vladG, that does look better (more Symphonic). ;-)
I am a bit baffled that your XML didn't contain any @id
s. Did you strip them out? The reason I am asking is because you should use @id
s rather than @handle
s to find related nodes. i.e.:
<xsl:apply-templates select="/data/docs/entry[chapter/item/@id = current()/title/@id]" />
Hi Nils, thanks for the tip.
Yes, I did leave out the id
s in the XML samples. Now I know they are important. :-)
I tried using id
s like in your example, but it doesn't work – I get an empty list.
Anything special I should be doing with the data sources?
Create an account or sign in to comment.
Hello,
I have a small question about XSLT and entries filtering, and am hoping that someone with more experience can point me in the right direction.
I'm trying to build a tree navigation for a collection of pages organized in chapters, using a jQuery plugin called simpleTreeMenu.
I got it to work nicely with static content, now I'm trying to make it dynamic and use data from my entries.
I have two sections,
Docs
andChapters
. Every entry inDocs
is assigned to aChapter
via a select box. So the tree menu needs two levels:I'm now half-way through, iterating through each chapter:
The part I'm having trouble with is the second iteration: listing all doc pages in each chapter (the commented spot). I tried listing all pages to start:
...but that doesn't work, I get an empty list. (The next step would be to filter this list by chapter.)
I feel this should be fairly easy to do, but I'm struggling to find the correct syntax.
Any tips? Thanks in advance!