Copied to clipboard

Flag this post as spam?

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


  • Roger 195 posts 474 karma points
    Sep 23, 2013 @ 15:01
    Roger
    0

    Help with XSLT search results filtering

    Hi,

    I have a search form and results page that all work great but I would like to select results based on EITHER the 2 search form fields or keywords.

    I have this code that works great:

            <xsl:variable name="dirtype" select="umbraco.library:RequestForm('dirtype')"/>
            <xsl:variable name="dirlocation" select="umbraco.library:RequestForm('dirlocation')"/>
            <xsl:variable name="dirkeywords" select="umbraco.library:RequestForm('dirkeywords')"/>

    <xsl:for-each select="$sectionNode[($dirtype=businessType) and ($dirlocation=businessArea)]">

    BUT -

    I need to change the select so that it basically states that if the keyword field 'dirkeywords' is blank, filter results on dirtype and dirlocation as it is above. Else filter results based on dirkeywords only.

    Can anyone help with this please?

    Thanks!

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Sep 23, 2013 @ 16:53
    Chriztian Steinmeier
    0

    Hi Roger,

    You should be able to do something like this:

    <xsl:for-each select="$sectionNode[
        ($dirtype = businessType)
        and ($dirlocation = businessArea)
        and (not(normalize-space($dirkeywords)))]
        |
        $sectionNode[(businessKeywords = $dirkeywords) and normalize-space($dirkeywords)]">
        <!-- Do something -->
    </xsl:for-each>
    

    The normalize-space() function returns false() for empty or whitespace-only strings, and the pipe (|) is a join operator - so you're joining two nodesets, but in effect you'll only ever get one of them, since they're mutually exclusive (one of them requires $dirkeywords to be empty, the other requires it to not be empty).

    /Chriztian

  • Roger 195 posts 474 karma points
    Sep 24, 2013 @ 11:34
    Roger
    0

    Hi Chriztian,

    Can I also use 'contains' instead of = here?

    $sectionNode[(businessKeywords = $dirkeywords) and normalize-space($dirkeywords)]"
  • Roger 195 posts 474 karma points
    Sep 24, 2013 @ 11:55
    Roger
    0

    Hi Chriztian,

    I've combined your solution with 'contains' and also used uppercase and lowercase variables:

    <xsl:variable name="lc">abcdefghijklmnopqrstuvwxyz</xsl:variable>
    <xsl:variable name="uc">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

    <xsl:for-each select="$sectionNode[($dirtype = businessType) and ($dirlocation = businessArea) and (not(normalize-space($dirkeywords)))] | $sectionNode[contains(translate(businessKeywords, $uc, $lc), $dirkeywords)  and normalize-space($dirkeywords)]">

    This seems to work fine. Unless you know of a better way of doing it?

    Thanks

    Roger

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Sep 24, 2013 @ 12:07
    Chriztian Steinmeier
    0

    Hey Roger,

    I was too slow :-)

    Yes that should work just fine - as long as you know there's no special characters going to appear in the keywords, and that the $dirkeywords variable is always uppercase.

    Otherwise, you could use the uppercase() extension in the Exslt.ExsltStrings class to get the "correct" (even taking .NET culture into account) uppercase versions of the strings...

    /Chriztian

  • Roger 195 posts 474 karma points
    Sep 24, 2013 @ 12:16
    Roger
    0

    Hi Chriztian,

    The keyword field could be either upper or lowercase. Also, I can't be certain that the comma separated keywords that the content managers add would all be lowercase. They might add them like:

    design,develop,web
    Design,Develop,WEB

    etc...

    The xslt would need to pull back results regardless of the case.

    I figured by using (businessKeywords, $uc, $lc) that results would write to screen regardless of case but i've just tested it and it doesnt work if the case doesnt match.

    Thanks

    Roger

  • Roger 195 posts 474 karma points
    Sep 24, 2013 @ 12:19
    Roger
    0

    Hi Chriztian,

    I've also just tried:

    $sectionNode[contains(businessKeywords, $dirkeywords) and normalize-space($dirkeywords)]"

    This also requires the case to be correct and fails if I use uppercase or capital first letter.

    It really needs to pull back results on any case variation

    thanks

    Roger

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Sep 24, 2013 @ 12:29
    Chriztian Steinmeier
    100

    Hi Roger - that's a very common problem - and you just need to compare the two in the same case, e.g. all lower or upper case.

    Perform the case-change where you initially grab the variable(s):

    <xsl:variable name="dirkeywords" select="Exslt.ExsltStrings:uppercase(umbraco.library:RequestForm('dirkeywords'))" />
    

    And compare using the uppercase version:

    $sectionNode[contains(Exslt.ExsltStrings:uppercase(businessKeywords), $dirkeywords) and normalize-space($dirkeywords)]
    

    /Chriztian

  • Roger 195 posts 474 karma points
    Sep 24, 2013 @ 12:36
    Roger
    0

    Hi Chriztian,

    That makes perfect sense and it works great!

    Many thanks for all the help as usual!

    Roger

  • Roger 195 posts 474 karma points
    Dec 09, 2013 @ 16:48
    Roger
    0

    Hi Chriztian,

    Just another one on search results please...

    I have a page that displays results based on a filter 'ftype' this is a simple dropdown with a button.

    <xsl:variable name="sectionNode" select="$currentPage/ancestor-or-self::*/Facilities/Facility"/>
    <xsl:variable name="ftype" select="umbraco.library:RequestForm('filter')"/>

    <xsl:for-each select="$sectionNode [($ftype=facilityType)]">

    the filter works fine but when a user first hits the page, I need to show them all records and the for-each to ignore [($ftype=facilityType)]

    What would i use to just show the values of $sectionNode?

    Thanks!

  • Chriztian Steinmeier 2800 posts 8791 karma points MVP 8x admin c-trib
    Dec 09, 2013 @ 22:59
    Chriztian Steinmeier
    1

    Hi Roger,

    There's a trick to do that - to understand how it works, you may need a little info on sets, though...

    Let's select a set of all the Textpage children of the current page, like this:

    <xsl:variable name="nodes" select="$currentPage/Textpage" />
    

    Now we can filter that set of nodes by adding one or more predicates, e.g. let's filter the hidden pages out:

    <xsl:variable name="visibleNodes" select="$nodes[not(umbracoNaviHide = 1)]" />
    

    So the predicate needs to evaluate to either true() or false(), right?

    Well, if you simply say [false()] you will get no nodes and likewise, if you supply [true()] you will get all nodes.

    That was the first part - the second part is that any node can exist only once in a nodeset, so if you do this:

    <xsl:variable name="moreNodes" select="$nodes | $nodes | $nodes" />
    

    You will only get a set consisting of all the nodes in the $nodes variable - you won't get any duplicates!

    So the trick is do this:

    <xsl:for-each select="$sectionNode[facilityType = $ftype] | $sectionNode[not($ftype)]">
    

    OK? So the last predicate will be false() if there was a value in the query string and subsequently, that nodeset will be empty; otherwise, if a query string value was not submitted, the predicate will be true() and thus, all the nodes returned. Effectively, we're combining two mutually exclusive sets, resulting in either the filtered set, or the complete set.

    Phew - hope that explains it :-)

    /Chriztian

  • Roger 195 posts 474 karma points
    Dec 10, 2013 @ 12:16
    Roger
    0

    Thanks Chriztian, makes perfect sense!

Please Sign in or register to post replies

Write your reply to:

Draft