I an relatively new to XSLT and I have many paintings represented as shown in the umbraco.config below and I which to automate a menu drop shows showing only "distict" "artWorkCategories". To do this I need a XLT ForEach statment which contains a XPath query with the equivilent on the SQL Select Distrinct functionality. To do this I have written the following For Each statment but it brings back all artWorkCategories including duplicates. Can you see what I am doing wrong and suggest a fix ?:
Distinct can be relatively tricky in XSLT - but it's of course doable.
At first glance, I'd try this (assuming all artworks are ArtWork documents in the same folder):
<!-- Collect all ArtWork documents in the folder -->
<xsl:variable name="artWorks" select="$AZDataNode/DataFolder[@nodeName = 'AZArtWorks']/ArtWork" />
<!-- Pick only those that doesn't have a preceding sibling with the same artWorkCategories value -->
<xsl:for-each select="$artWorks[not(preceding-sibling::ArtWork/artWorkCategories = current()/artWorkCategories)]">
<!-- ... -->
</xsl:for-each>
There's a small caveat to this approach, though:
It will not work correct if the artWorkCategories property can contain more than one category (which its name kind of suggests :-)
Thanks for your reply, but unfortunately your reply is missing your actual suggestion. See here.
Also at this time I am only planing for each ArtWork to have only one "artWorkCategories" (despite the name). In any case it would be good to get that going first.
Thanks very much for your assistance. Your approach is great, I did have to make one small change to get it to work, I removed the following code from your for-each statement:
current()/
Thus the final code that worked is
<!-- Collect all ArtWork documents in the folder --> <xsl:variablename="artWorks"select="$AZDataNode/DataFolder[@nodeName = 'AZArtWorks']/ArtWork"/>
<!-- Pick only those that doesn't have a preceding sibling with the same artWorkCategories value --> <xsl:for-eachselect="$artWorks[not(preceding-sibling::ArtWork/artWorkCategories = artWorkCategories)]"> <!-- ... --> </xsl:for-each>
Also, now that that is working, I am now also wondering if I can support multiple artWorkCategoreis, and if there is a "contains" operator I could use in place of the "=" operator in the for-each statement to achieve this.
The current() function is perfectly valid — been using that for years :) (and please don't regard the W3Schools site's info as "the truth" for that matter ;-) — however, I used it wrongly here because of a last minute switch-around in the example, and removing should definitely work in your case.
To support multiple categories, you can use the contains() function - something like this:
Using XPath Select Distinct in an WSLT For Each
Dear XSLTers,
I an relatively new to XSLT and I have many paintings represented as shown in the umbraco.config below and I which to automate a menu drop shows showing only "distict" "artWorkCategories". To do this I need a XLT ForEach statment which contains a XPath query with the equivilent on the SQL Select Distrinct functionality. To do this I have written the following For Each statment but it brings back all artWorkCategories including duplicates. Can you see what I am doing wrong and suggest a fix ?:
>>>>>
<xsl:for-each select="$AZDataNode/DataFolder[@nodeName='AZArtWorks']/*[not(artWorkCategories=preceding-sibling::DataFolder[@nodeName='AZArtWorks']/artWorkCategories)]">
<<<<<
Here is the excerptumbraco.config from :
<DataFolder id="1063" parentID="1050" level="2" creatorID="0" sortOrder="1" createDate="2013-06-11T23:52:03" updateDate="2013-06-12T00:27:18" nodeName="AZArtWorks" urlName="azartworks" path="-1,1050,1063" isDoc="" nodeType="1049" creatorName="admin" writerName="admin" writerID="0" template="1048" nodeTypeAlias="DataFolder">
<ArtWork id="1070" parentID="1063" level="3" creatorID="0" sortOrder="0" createDate="2013-06-12T00:10:28" updateDate="2013-09-11T20:28:32" nodeName="IngridClancy Painting CoffeeShopLove" urlName="ingridclancy-painting-coffeeshoplove" path="-1,1050,1063,1070" isDoc="" nodeType="1065" creatorName="admin" writerName="admin" writerID="0" template="0" nodeTypeAlias="ArtWork">
<artWorkTitle><![CDATA[Coffee Shop Love]]></artWorkTitle>
<artist><![CDATA[Painting]]></artist>
<artWorkFile>/media/1001/ingridclancy_painting_coffeeshoplove-w480.jpg</artWorkFile>
<artWorkDescription><![CDATA[]]></artWorkDescription>
<artWorkOriginalWidth />
<artWorkOriginalHeightCm />
<artCreationDate />
<artWorkCategories><![CDATA[Painting]]></artWorkCategories>
<forSale><![CDATA[]]></forSale>
<price><![CDATA[]]></price>
<artistNameID><![CDATA[IngridClancy]]></artistNameID>
</ArtWork>
<ArtWork id="1072" parentID="1063" level="3" creatorID="0" sortOrder="1" createDate="2013-06-12T00:19:02" updateDate="2013-09-11T20:28:25" nodeName="IngridClancy_Painting_FlowerPot" urlName="ingridclancy_painting_flowerpot" path="-1,1050,1063,1072" isDoc="" nodeType="1065" creatorName="admin" writerName="admin" writerID="0" template="0" nodeTypeAlias="ArtWork">
<artWorkTitle><![CDATA[Flower Pot]]></artWorkTitle>
<artist><![CDATA[Painting]]></artist>
<artWorkFile>/media/1004/ingridclancy_painting_flowerpot-w640.jpg</artWorkFile>
<artWorkDescription><![CDATA[]]></artWorkDescription>
<artWorkOriginalWidth />
<artWorkOriginalHeightCm />
<artCreationDate />
<artWorkCategories><![CDATA[Painting]]></artWorkCategories>
<forSale><![CDATA[]]></forSale>
<price><![CDATA[]]></price>
<artistNameID><![CDATA[IngridClancy]]></artistNameID>
</ArtWork>
Thanks Terry Clancy
Hi Terry,
Distinct can be relatively tricky in XSLT - but it's of course doable.
At first glance, I'd try this (assuming all artworks are ArtWork documents in the same folder):
There's a small caveat to this approach, though:
Let me know if it helps,
/Chriztian
Chriztian,
Thanks for your reply, but unfortunately your reply is missing your actual suggestion. See here.
Also at this time I am only planing for each ArtWork to have only one "artWorkCategories" (despite the name). In any case it would be good to get that going first.
Thanks again
Terry
Hey Terry,
Sorry 'bout that - I just edited the answer; it was all there - I had just forgotten to mark it as code :-)
/Chriztian
Chriztian,
Thanks very much for your assistance. Your approach is great, I did have to make one small change to get it to work, I removed the following code from your for-each statement:
Thus the final code that worked is
I also note that could not see current() as a function at http://www.w3schools.com/xpath/xpath_functions.asp, and I am wondering if it is valid.
Also, now that that is working, I am now also wondering if I can support multiple artWorkCategoreis, and if there is a "contains" operator I could use in place of the "=" operator in the for-each statement to achieve this.
Thanks again for your assistance.
Terry
Hi Terry,
The
current()
function is perfectly valid — been using that for years :) (and please don't regard the W3Schools site's info as "the truth" for that matter ;-) — however, I used it wrongly here because of a last minute switch-around in the example, and removing should definitely work in your case.To support multiple categories, you can use the
contains()
function - something like this:— but beware of the "danger" of having categories like "cake" and "pancakes" - "pancakes" contains "cake", so you'll get a false positive there...
You may also check this thread where we use the
Split()
extension to achieve a similar thing without the danger of the above.../Chriztian
Chriztian,
Great - thanks very much for your help with this, very much appreciated.
Terry
is working on a reply...