Reputation: 123
I've had a bit of experience with XSL, but what I need now is a bit above my skill set, and I'm a bit confused as to how to tackle it. I've also looked around this site, and don't think I found something quite like it...although I may be wrong!
To begin, here is some XML that my page is generating:
<root>
<content>
<Title>Title 1 here</Title>
<Image>Image Link 1 here</Image>
<Description>Description 1 here</Description>
<Category>Special Exhibitions</Category>
<Priority>2</Priority>
</content>
<content>
<Title>Title 2 here</Title>
<Image>Image Link 2 here</Image>
<Description>Description 2 here</Description>
<Category>Special Exhibitions</Category>
<Priority>1</Priority>
</content>
<content>
<Title>Title 3 here</Title>
<Image>Image Link 3 here</Image>
<Description>Description 3 here</Description>
<Category>Live Music</Category>
<Priority>9</Priority>
</content>
<content>
<Title>Title 4 here</Title>
<Image>Image Link 4 here</Image>
<Description>Description 4 here</Description>
<Category>Lecture</Category>
<Priority>7</Priority>
</content>
<content>
<Title>Title 5 here</Title>
<Image>Image Link 5 here</Image>
<Description>Description 5 here</Description>
<Category>Special Exhibitions</Category>
<Priority>3</Priority>
</content>
<content>
<Title>Title 6 here</Title>
<Image>Image Link 6 here</Image>
<Description>Description 6 here</Description>
<Category>Workshop</Category>
<Priority>10</Priority>
</content>
<content>
<Title>Title 7 here</Title>
<Image>Image Link 7 here</Image>
<Description>Description 7 here</Description>
<Category>Special Exhibitions</Category>
<Priority>6</Priority>
</content>
</root>
Basically, each <content>
element has various children, including <Category>
and <Priority>
.
My issue is that I want to select just the first node with <Category=Special Exhibition>
, ordered by <Priority>
, so in this case, "Title 2".
Here is what I have as XSL so far:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="root/EventType/Type">
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Type">
<xsl:variable name="categoryType" select="." />
<xsl:apply-templates select="../../content[Category=$categoryType]">
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="root/content">
<xsl:sort data-type="number" order="ascending" select="Priority"/>
<xsl:if test="(Category='Special Exhibitions')">
<xsl:choose>
<xsl:when test="(position()=1)">
<div class="slide-container">
<img style="margin-top:18px;" src="{BannerImage}" alt="{Title}" title="{Title}"/>
<span>
<xsl:attribute name="class">
<xsl:text>slide-caption</xsl:text>
</xsl:attribute>
<xsl:value-of select="Title"></xsl:value-of>
<xsl:text> | </xsl:text>
<xsl:value-of select="Date"></xsl:value-of>
</span>
</div>
</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Obviously my problem is somewhere inside the <xsl:if>
and <xsl:when>
section. This is how my mind thinks of finding the node, but obviously not the way XSL does! Can anyone give me a pointer on how to attack this?
Thanks so much in advance-
Upvotes: 2
Views: 3530
Reputation: 27994
Without knowing what result you're actually getting, as opposed to the result you want, I would say change these lines:
<xsl:for-each select="root/content">
<xsl:sort data-type="number" order="ascending" select="Priority"/>
<xsl:if test="(Category='Special Exhibitions')">
<xsl:choose>
<xsl:when test="(position()=1)">
to
<xsl:for-each select="root/content[Category='Special Exhibitions']">
<xsl:sort data-type="number" order="ascending" select="Priority"/>
<xsl:if test="position()=1">
I say this because you want to process "the first node with <Category=Special Exhibition>
, ordered by <Priority>
", whereas you are processing *the first (root/content) node ordered by <Priority>
, if that node happens to have <Category>=Special Exhibition
.
In the case where the lowest-Priority content does not belong to the Special Exhibition category, your original code would output nothing. Granted this is not the case with the sample input you showed. But since you haven't told us what the actual output is for that sample, this is my best guess based on the available data.
Upvotes: 1
Reputation: 7184
Don't use sort or when. Select the node you want with xpath:
<xsl:template match="/">
<xsl:for-each select="/root/content
[Category = 'Special Exhibitions']
[Priority = min(/root/content[Category =
'Special Exhibitions']/Priority)]
[1]">
<div class="slide-container">
<img style="margin-top:18px;" src="{BannerImage}" alt="{Title}" title="{Title}"/>
<span class="slide-caption">
<xsl:value-of select="concat(Title, ' | ', Date)"/>
</span>
</div>
</xsl:for-each>
Or, with XPath 1.0:
<xsl:for-each select="/root/content
[Category = 'Special Exhibitions']
[not(Priority > /root/content[Category =
'Special Exhibitions']/Priority)]
[1]">
Upvotes: 2