Press Ctrl / CMD + C to copy this to your clipboard.
This post will be reported to the moderators as potential spam to be looked at
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)]">
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?
You should be able to do something like this:
($dirtype = businessType)
and ($dirlocation = businessArea)
$sectionNode[(businessKeywords = $dirkeywords) and normalize-space($dirkeywords)]">
<!-- Do something -->
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).
Can I also use 'contains' instead of = here?
$sectionNode[(businessKeywords = $dirkeywords) and normalize-space($dirkeywords)]"
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?
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...
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:
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.
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
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)]
That makes perfect sense and it works great!
Many thanks for all the help as usual!
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?
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 :-)
Thanks Chriztian, makes perfect sense!
is working on a reply...
Write your reply to:
Image will be uploaded when post is submitted