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 941 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 2726 posts 8320 karma points MVP 4x 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 941 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 2726 posts 8320 karma points MVP 4x 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 941 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 2726 posts 8320 karma points MVP 4x 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 941 karma points
    Sep 17, 2013 @ 16:09
    Terry Clancy
    0

    Chriztian,

     

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

     

    Terry

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies