Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Terry Clancy 204 posts 944 karma points
    Sep 13, 2013 @ 09:01
    Terry Clancy
    0

    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

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Sep 13, 2013 @ 09:36
    Chriztian Steinmeier
    0

    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):

    <!-- 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 :-)

    Let me know if it helps,

    /Chriztian

  • Terry Clancy 204 posts 944 karma points
    Sep 13, 2013 @ 19:33
    Terry Clancy
    0

    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

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Sep 13, 2013 @ 20:26
    Chriztian Steinmeier
    0

    Hey Terry,

    Sorry 'bout that - I just edited the answer; it was all there - I had just forgotten to mark it as code :-)

    /Chriztian

  • Terry Clancy 204 posts 944 karma points
    Sep 17, 2013 @ 01:57
    Terry Clancy
    100

    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:

    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>

    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

     

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Sep 17, 2013 @ 09:07
    Chriztian Steinmeier
    0

    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:

    <xsl:for-each select="$artWorks[not(contains(preceding-sibling::ArtWork/artWorkCategories, artWorkCategories))]">
        ...
    </xsl:for-each>
    

    — 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

  • Terry Clancy 204 posts 944 karma points
    Sep 17, 2013 @ 16:09
    Terry Clancy
    0

    Chriztian,

     

    Great - thanks very much for your help with this, very much appreciated.

     

    Terry

Please Sign in or register to post replies

Write your reply to:

Draft