Reputation: 399
Hey guys, what I am wanting to create is a mini timetable for a zoo.
Below is a ms paint mockup of the functionality. What im looking to have is a list of times horizontally up top, and when you click on one, the page moves down to that time slot and shows its details.
Exactly like anchor tags in HTML and my data is stored in XML.
So here is my xml data:
<zoo>
<animal name="Lion">
<feeding-time>11:00</feeding-time>
</animal>
<animal name="Penguin">
<feeding-time>14:00</feeding-time>
</animal>
<animal name="Elephant">
<feeding-time>9:00</feeding-time>
</animal>
<animal name="Tortoise">
<feeding-time>11:00</feeding-time>
</animal>
<animal name="Ape">
<feeding-time>16:00</feeding-time>
</animal>
<animal name="Hippo">
<feeding-time>14:00</feeding-time>
</animal>
<animal name="Rattle Snake">
<feeding-time>9:00</feeding-time>
</animal>
<animal name="Flamingo">
<feeding-time>15:00</feeding-time>
</animal>
</zoo>
And my XSL page is pretty bland:
<xsl:template match="/">
<html>
<head>
<title>Real Estate Listings</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I know that I need to use Locator paths using axes and/or Meunchian grouping - and I have researched this for hours and I still dont have any idea whats going on.
I know that I need to use the generate-id function, and use the key function is well but again, I have no idea how to implement it - iv spent hours and hours on google trying to figure this stuff out.
Any help would be orsome.
Upvotes: 1
Views: 3899
Reputation: 12075
Muenchian grouping uses a key defined at the root level of the XSLT sheet, that allows the key
function to return a list of all elements that meet a given criteria, and then picks the first item from that list. For example:
<xsl:key name="feedingTime" match="*" use="feeding-time" />
This allows you to call key('feedingTime','11:00')
to get a list of all elements who have a feeding-time
element with a value of 11:00
.
You can use this in a template with the generate-id()
function, which returns a unique value of each ID. You do this by comparing the id of the element you're currently processing, with the id of the first element in the list of all elements with the same feeding-time
value. Like this:
<xsl:if test="generate-id(feeding-time) = generate-id(key('feeding-time',feeding-time)[1])">
<!-- generate output -->
</xsl:if>
Or, you can use the same condition in a template match, and use the same key to iterate through the list of animal
nodes with the current feeding time:
<xsl:template match="animal[generate-id() = generate-id(key('feedingTime',feeding-time)[1])]">
<!-- output a heading here, current node is first animal node with each feeding-time -->
<xsl:for-each select="key('feedingTime',feeding-time)">
<!-- output each animal here -->
</xsl:for-each>
</xsl:template>
If you do this, you need to include an empty template like this: <xsl:template match="animal" />
to handle the remaining animal
elements, discarding them; you already dealt with them in for-each
loop of the above template.
You can use template modes to process the list separately for the links and the content below like this:
<xsl:key name="feedingTime" match="*" use="feeding-time" />
<xsl:template match="zoo">
<xsl:apply-templates mode="links" />
<xsl:apply-templates mode="content" />
</xsl:template>
<xsl:template match="animal[generate-id() = generate-id(key('feedingTime',feeding-time)[1])]" mode="links">
<a href="#time_{feeding-time}">
<xsl:value-of select="feeding-time" />
</a>
</xsl:template>
<xsl:template match="animal[generate-id() = generate-id(key('feedingTime',feeding-time)[1])]" mode="content">
<p id="time_{feeding-time}">
<xsl:value-of select="concat(feeding-time,' Feeding time for:')" />
</p>
<ul>
<xsl:for-each select="key('feedingTime',feeding-time)">
<li>
<xsl:value-of select="@name" />
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="animal" mode="links" />
<xsl:template match="animal" mode="content" />
The two templates at the bottom are to handle all animal
elements that aren't handled by the previous ones (i.e., the 2nd and subsequent animal
element for each feeding-time). I haven't handled the formatting here, but hopefully it should demonstrate techniques that should help you.
Upvotes: 0
Reputation: 243599
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kTimeByVal" match="feeding-time"
use="."/>
<xsl:key name="kAnimalByTime" match="@name"
use="../feeding-time"/>
<xsl:template match="/">
<xsl:apply-templates/>
<xsl:apply-templates mode="group"/>
</xsl:template>
<xsl:template match=
"feeding-time[generate-id()
=
generate-id(key('kTimeByVal',.)[1])
]
">
<a href="#{generate-id()}">
<xsl:value-of select="."/>
</a>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template mode="group" match=
"feeding-time[generate-id()
=
generate-id(key('kTimeByVal',.)[1])
]
">
<br /><p id="{generate-id()}"><xsl:text/>
<b><xsl:value-of select="."/> Feeding Time for:</b></p>
<xsl:apply-templates select="key('kAnimalByTime', .)"/>
</xsl:template>
<xsl:template match="@name">
<br /><xsl:value-of select="."/>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template mode="group" match="text()"/>
</xsl:stylesheet>
when applied to the provided XML document:
<zoo>
<animal name="Lion">
<feeding-time>11:00</feeding-time>
</animal>
<animal name="Penguin">
<feeding-time>14:00</feeding-time>
</animal>
<animal name="Elephant">
<feeding-time>9:00</feeding-time>
</animal>
<animal name="Tortoise">
<feeding-time>11:00</feeding-time>
</animal>
<animal name="Ape">
<feeding-time>16:00</feeding-time>
</animal>
<animal name="Hippo">
<feeding-time>14:00</feeding-time>
</animal>
<animal name="Rattle Snake">
<feeding-time>9:00</feeding-time>
</animal>
<animal name="Flamingo">
<feeding-time>15:00</feeding-time>
</animal>
</zoo>
produces exactly the wanted result:
<a href="#d0e5">11:00</a>
<a href="#d0e11">14:00</a>
<a href="#d0e17">9:00</a>
<a href="#d0e29">16:00</a>
<a href="#d0e47">15:00</a>
<br/>
<p id="d0e5">
<b>11:00 Feeding Time for:</b>
</p>
<br/>Lion<br/>Tortoise<br/>
<p id="d0e11">
<b>14:00 Feeding Time for:</b>
</p>
<br/>Penguin<br/>Hippo<br/>
<p id="d0e17">
<b>9:00 Feeding Time for:</b>
</p>
<br/>Elephant<br/>Rattle Snake<br/>
<p id="d0e29">
<b>16:00 Feeding Time for:</b>
</p>
<br/>Ape<br/>
<p id="d0e47">
<b>15:00 Feeding Time for:</b>
</p>
<br/>Flamingo
And it displays in the browser exactly as wanted, and has the wanted (link-clicking) behavior:
11:00
14:00
9:00
16:00
15:00
Lion
Tortoise
Penguin
Hippo
Elephant
Rattle Snake
Ape
Flamingo
Explanation: Muenchian grouping, using generate-id()
for generating unique ids to use as anchors, using keys.
Upvotes: 2