Copied to clipboard

Flag this post as spam?

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


  • Rich Green 2246 posts 4008 karma points
    Mar 20, 2010 @ 12:17
    Rich Green
    0

    Matching multiple comma separated values

    Hi,

    In XSLT how would I achieve the following?

    I have comma seperated search values of (1,2,8) 

    I need to see which products have all these attributes, so for example

    Product 1 attributes - (1,3,4)

    Product 2 attributes - (1,2,3,4,5,8,10)

    Product 3 attributes - (1,2,5,8)

    So in this example Product 2 & 3 would match as they both have attributes of 1, 2 & 8.

    I'm not looking for advice on the structure and nodes as such as I've have this in place, just the problem above!

    Would appreciate any advice, many thanks

    Rich

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Mar 20, 2010 @ 23:10
    Douglas Robar
    2

    Hi, Rich,

    Here's the general idea... do a split() on the search values. Then do a for-each on each of those values to see if your product atttributes contain that value.

    Something like this (not tested):

    <xsl:for-each select="split($searchAttribs, ',') ">
    <xsl:variable name="searchAttrib" select="." />
    <xsl:for-each select="$product" >
    <xsl:variable name="productAttribs" select="concat(",", ./data[@alias='attribs'], ",")" />
    <xsl:if test="contains($productAttribs, concat(",", $searchAttrib, ","))" >
    <xsl:value-of select="./@nodeName" />
    </xsl:if>
    </xsl:for>
    </xsl:for-each>

    cheers,

    doug.

  • Rich Green 2246 posts 4008 karma points
    Mar 21, 2010 @ 13:48
    Rich Green
    0

    Hey Doug,

    Thanks for your reply. However I'm not sure this will work in this case.

    Hopefully this clarifies it, here's pretty much what I'm trying to do

    <xsl:variable name="searchterm">,3,1,</xsl:variable>
    <xsl:variable name="productattributes">,1,7,3,2,</xsl:variable>
    
    <xsl:if test="contains($searchterm, $productattributes)">
        (this returns false, but I need a function to return True
        as the product has both '1' and '3' as attributes and therefore should return in the search)
    </xsl:if>

     

    The way in theory I could solve this are:

     

    1. Sort the search term = (,1,3,)
    2. Loop through all the product attributes and remove any attributes not in the search term = (,1,3,)
    3. Sort the filtered product attributes = (,1,3,)
    4. Then see if they match - contains(',1,3,' , ',1,3,') = True
    However there might be a better way?
    Many thanks

    Rich

     

  • Nik Wahlberg 639 posts 1237 karma points MVP
    Mar 21, 2010 @ 14:53
    Nik Wahlberg
    0

    Hi Rich, 

    A 'contains' won't work as that will match the string that you're getting from your search term. In the example above, the productattributes does not contain the string ",1,3,". So, I think what you would need (borrowing from Dougs example above) is something like this:

        <xsl:for-each select="umbraco.library:Split($searchAttribs, ',')">
          <xsl:variable name="searchAttrib" select="." />
          <xsl:for-each select="$products" >
            <xsl:for-each select="umbraco.library:Split(./data[@alias='attribs'], ',')">
              <xsl:variable name="productAttrib" select="." />
              <xsl:if test="$productAttrib=$searchAttrib" >
                <xsl:value-of select="./@nodeName" />
              </xsl:if>
            </xsl:for-each>
          </xsl:for-each>
        </xsl:for-each>

    Now, if we had access to 2.0 then we could have done an index-of, but since we don't then this rather (potentially) expensive nested loop is the best approach (as I see it). 

    Hope this works.

    -- Nik

     

  • Chris Koiak 700 posts 2626 karma points
    Mar 21, 2010 @ 18:41
    Chris Koiak
    1

    Hi Rich,

    I'd still try the 'split' approach as I had a very similar problem recently and this worked for me. try

    <xsl:variable name="searchterm">,3,1,</xsl:variable>
    <xsl:variable name="productattributes">,1,7,3,2,</xsl:variable>

    <xsl:if test="contains($productattributes,umbraco.library:Split($searchterm)/value)">
    </xsl:if>

    You may have to run a split on the first list too (I can't quite remember if I had to do that).

    This should also avoid any complex looping

    Cheers,

    Chris

  • Rich Green 2246 posts 4008 karma points
    Mar 22, 2010 @ 22:44
    Rich Green
    0

    Hi Chris / Nik,

    Thanks for your replies. 

    Chris, I tried your code but got the following error:

    System.Xml.Xsl.XslTransformException: To use a result tree fragment in a path expression, first convert it to a node-set using the msxsl:node-set() function. 

    Using this code:

    <xsl:variable name="searchterms">1369,1064</xsl:variable>
    <xsl:variable name="productattributes">1064,1372,1369</xsl:variable>
    <xsl:if test="contains(umbraco.library:Split($productattributes/value,','), umbraco.library:Split($searchterms/value,','))">
        Match
    </xsl:if>

    Real shame because that would have been perfect, please let me know if I've coded it incorrectly.

    Nik, I'm close to get it all working using an expensive loop similar to your code, which may have to do for now!

    Would be interested to hear any other solutions too, prehaps using C# / LINQ?

    Cheers

    Rich

  • Jesper Hauge 298 posts 487 karma points c-trib
    Mar 23, 2010 @ 00:09
    Jesper Hauge
    0

    Hi Rich

    Problem is you're doing the split on $productattributes/value, the /value part should be appended to the split function, since the split function returns a node set of value nodes beneath a values node. And you don't need to do a split, on both strings, just one of them, and then use contains with prepended and appended commas to match exact id's like this:

    <xsl:variable name="searchterms">1369,1064</xsl:variable>
    <xsl:variable name="productattributes">1064,1372,1369</xsl:variable>
    <xsl:variable name="searchvalues" select="umbraco.library:Split($searchterms, ',')" />
    
    <xsl:for-each select="$searchvalues/value">
        <xsl:if test="contains(concat(',', $productattributes), concat(',', string(.), ','))">
            Match
        </xsl:if>
    </xsl:for-each>

    Regards
    Jesper Hauge

  • Rich Green 2246 posts 4008 karma points
    Mar 23, 2010 @ 08:20
    Rich Green
    0

    Hi Jesper,

    Thanks for your reply, however unless I'm mistaken your code will match products with EITHER attribute 1369 OR 1064.

    The problem is that I want to return only products which have match ALL search terms.

    Hence I need to loop through and keep hold of the values somehow, unless there was some call to the CONTAINS function which would do this, something similar to Chris's code, which unfortunately I couldn't get to work.

    Looks like a expensive loop is the only way to go in XSLT?

    Cheers

    Rich

  • Nikolas van Etten 202 posts 162 karma points
    Mar 23, 2010 @ 09:36
    Nikolas van Etten
    0

    I ran into a similar problem when making a related pages xslt file based on tags. To solve it I created a temp nodeset and saved all matches there. Then another nodeset where I grouped the matches and weighted them. Performance wise not the best, but seems to work fine with the website I made it for at least. The weighting (which just counts how many times a specific node has been listed in the temp nodeset) could be used to find the correct matches.

     

Please Sign in or register to post replies

Write your reply to:

Draft