Curious why you'd want to do it with the <xsl:text> ?
The problem here is that when you use <xsl:text> in the <xsl:variable> the <xsl:for-each> is treating it as a string - as opposed to a XPath statement.
Damn, cross-posts with Shaun at the same time, (keeps happening to me lately!)
@Lee - does the "/root" bit work for you? (in your original post's snippet). As the XML context of the first <xsl:template match="/"> is for the <macro> parameters. For "/root" to work, you'd need to use:
$currentPage/ancestor::root
or how most of us use Umbraco by having the @level=1 as the homepage node - and all other pages below that, you could use:
Thanks for the reponses chaps - The problem I have is I am trying to build up the select in a variable (i.e.)
<!-- ############ Build up the select ############## -->
<xsl:variable name="thesearch">
<xsl:text>/root//node [string-length(./data [@alias = 'distance']) > 0 and number(./data [@alias = 'distance']) < $radius and umbraco.library:DateGreaterThanOrEqualToday(./data [@alias='eventDate'])</xsl:text>
<xsl:if test="string(umbraco.library:Request('area')) != '' ">
<xsl:text> and string(./data [@alias ='eventCounty']) = </xsl:text>
<xsl:text>'</xsl:text><xsl:value-of select="umbraco.library:Request('area')" /><xsl:text>'</xsl:text>
</xsl:if>
<xsl:text>]</xsl:text>
</xsl:variable>
<!-- ############ End Select ############## -->
This is why I couldn't use select="" for the varaible, and needed to build it up inbetween (The above is only an example there are a lot more if's and choose's to be put in)
@Shaun - I'll try that value of instead
@Lee - Yes the root bit works, its from Tims locator package and I'm just trying to extend it :)
Might be a stupid question, but you can cast to string in XSLT but can I cast as XPath Statement? Or do something in C# and I'll make a custom extension?
Rather frustrating as what I'm trying to do isn't anything out the ordinary? Or is it?
There are a few ways of doing this in XSLT, but here's a super-quick way:
<!-- ############ Build up the select ############## -->
<xsl:variable name="area" select="string(umbraco.library:Request('area'))" />
<xsl:variable name="thesearch">
<xsl:choose>
<xsl:when test="$area != ''">
<xsl:value-of select="/root//node[string-length(data[@alias='distance']) > 0 and number(data[@alias='distance']) < $radius and umbraco.library:DateGreaterThanOrEqualToday(data[@alias='eventDate']) and string(data[@alias ='eventCounty']) = $area]" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="/root//node[string-length(data[@alias='distance']) > 0 and number(data[@alias='distance']) < $radius and umbraco.library:DateGreaterThanOrEqualToday(data[@alias='eventDate'])]" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- ############ End Select ############## -->
Instead of trying to build-up the XPath (as a string), as you might do in "old skool" ASP/SQL type-of-way, you use a <xsl:choose> to select the appropriate XPath statement. I know there is some duplication here ... but it's straight-forward to understand and does the job.
Cheers, Lee.
PS. If I find a better way, I'll let you know. ;-)
The problem is that the text in the "XPath string" needs to be evaluated before it is sent to the GetXmlNodeByXPath method.
Meaning that any variables or XSLT extension method calls need to be resolved beforehand... as they have no context in the GetXmlNodeByXPath method.
The way I tried to tackle this is to do a literal output of the desired XPath:
<!-- ############ Build up the select ############## -->
<xsl:variable name="thesearch">
<xsl:text>/root//node[string-length(data[@alias='distance']) > 0 and number(data[@alias='distance']) < </xsl:text>
<xsl:value-of select="$radius" />
<xsl:text> and ( number(translate(data[@alias='eventDate'], '-:T', '')) >= number(translate('</xsl:text>
<xsl:value-of select="umbraco.library:CurrentDate()" />
<xsl:text>', '-:T', '')) )]</xsl:text>
</xsl:variable>
<!-- ############ End Select ############## -->
Specifically, outputting the $radius variable and changing the DateGreaterThanOrEqualToday to a different (literal) way, (removing bits of the date-string and casting it as a number).
This had me stumped for a while, it's got to be incredibly frustrating for an XSLT beginner.
Due to the complexity of this, it might be better to pursue an alternative approach? Say in C#? or maybe email/twitter Tim for alternative suggestions?
You'll have some C# functions (in an xslt extension or right in your xslt file) along these lines...
public XmlNodes evaluatexpath(XmlNodes nodeset, string xpath){ return nodeset.SelectNodes(xpath); }
or: public string evaluatexpath(XmlNodes nodeset, string xpath){ return nodeset.Evaluate(xpath); }
I think you want Evaluate if you're returning a value (here, I assume a string) and SelectNodes if you actually want to return a node set... which means two separate functions
You might need to return an iterator of some kind, rather than XmlNodes, but you definitely need to do an evaluation of the xpath string, which I think can only be done in c#
Sorry I can't do more than point the way right now.
Ok after hours of Googling it seems that a lot of people have the same problem I am having and to get round it they either use
exslt:node-set()
or
msxsl:node-set()
I'm trying to use msxsl:node-set() as I thought this namespace was part of my XSLT file but I keep getting 'prefix msxsl is not defined' any ideas how I can get it to recognise this function? This is the top of my XSLT file
Notes from my wonderful wife who is (among many other talents) a fantastic xslt guru...
"the problem is he's now trying to assign a node set to a variable but "within" the variable tags not in the "select" attribute he needs to have: <xsl:variable name="xpath" select="blah blah blah"/> <xsl:variable name="searchResults" select="umbraco.library:GetXmlNodeByXPath($xpath)"/> and it'll work just fine
one variable for the xpath one variable for the nodeset
but WHENEVER there's a nodeset, it must always be in a "select" bit NEVER within the variable or it turns into a string and that's a nuisance
well, it can be done you just need some c# to stitch it back together again"
Well, there you have it.
DM me if you need help working it up to a full solution.
Weird XSLT Problem?
And there I was thinking I had got my head round XSLT... Could someone tell me why the below is now working
This works fine on my page
But this doesn't
I don't see any difference??? I need to build up a select string so need to put it in a variable???
I'm equally thrown by XSLT, does this work?
Hi Lee,
Curious why you'd want to do it with the <xsl:text> ?
The problem here is that when you use <xsl:text> in the <xsl:variable> the <xsl:for-each> is treating it as a string - as opposed to a XPath statement.
If you did this:
then that would work fine.
Damn, cross-posts with Shaun at the same time, (keeps happening to me lately!)
@Lee - does the "/root" bit work for you? (in your original post's snippet). As the XML context of the first <xsl:template match="/"> is for the <macro> parameters. For "/root" to work, you'd need to use:
or how most of us use Umbraco by having the @level=1 as the homepage node - and all other pages below that, you could use:
as your pseudo "root" node?
Cheers, Lee.
Thanks for the reponses chaps - The problem I have is I am trying to build up the select in a variable (i.e.)
This is why I couldn't use select="" for the varaible, and needed to build it up inbetween (The above is only an example there are a lot more if's and choose's to be put in)
@Shaun - I'll try that value of instead
@Lee - Yes the root bit works, its from Tims locator package and I'm just trying to extend it :)
Thanks again for helping chaps, appreciated
Hmmm still not working :(
Might be a stupid question, but you can cast to string in XSLT but can I cast as XPath Statement? Or do something in C# and I'll make a custom extension?
Rather frustrating as what I'm trying to do isn't anything out the ordinary? Or is it?
Hi Lee,
There are a few ways of doing this in XSLT, but here's a super-quick way:
Instead of trying to build-up the XPath (as a string), as you might do in "old skool" ASP/SQL type-of-way, you use a <xsl:choose> to select the appropriate XPath statement. I know there is some duplication here ... but it's straight-forward to understand and does the job.
Cheers, Lee.
PS. If I find a better way, I'll let you know. ;-)
Hi Lee,
OK, figured it... there is an umbraco.library method called "GetXmlNodeByXPath", here's how you can use it:
It takes a string input and queries the entire site (nodes that are published in the XML cache).
I knew there was something already available, just needed time to figure it out! ;-)
Good luck, Lee.
Thanks for the help Lee :)
Unfortunately its still not working? I have tried it like so but to no avail
And tried your first solution? Still it seems to only work if I actually do it like this????
I'm a touch gobsmacked at the moment :(
Ahhhhhhhhhhhh ok I admit it, I just don't get XSLT... Why does this work fine and returns the correct XML
And this just dies??
What the **** is going on.. lol!
P.S. Anyone have a rope?
Following up on my tweet: http://twitter.com/leekelleher/status/6728632401
The problem is that the text in the "XPath string" needs to be evaluated before it is sent to the GetXmlNodeByXPath method.
Meaning that any variables or XSLT extension method calls need to be resolved beforehand... as they have no context in the GetXmlNodeByXPath method.
The way I tried to tackle this is to do a literal output of the desired XPath:
oh, another quickie... I'll leave it alone after this... try copy-of instead of value-of:
Here's my two pence worth (and, with inflation, even that isn't the value it once was)...
Use C# and the .Evaluate() capabilities. I don't have a full example handy but you should be able to get there with these (rather fragmented) notes...
<xsl:copy-of select="ps:evaluatexpath(myNodeSet, myXpath")/>
You may also need to use the string2xml code available on the 'net if some cases. http://lenzconsulting.com/xml-to-string/
You'll have some C# functions (in an xslt extension or right in your xslt file) along these lines...
public XmlNodes evaluatexpath(XmlNodes nodeset, string xpath){
return nodeset.SelectNodes(xpath);
}
or:
public string evaluatexpath(XmlNodes nodeset, string xpath){
return nodeset.Evaluate(xpath);
}
I think you want Evaluate if you're returning a value (here, I assume a string) and SelectNodes if you actually want to return a node set... which means
two separate functions
You might need to return an iterator of some kind, rather than XmlNodes, but you definitely need to do an evaluation of the xpath string, which I think can only be done in c#
Sorry I can't do more than point the way right now.
cheers,
doug.
hehehe thanks - but I tried that one in the hope I was being a plank, but it still doesn't work :(
Not really sure which way to turn now, as Tims package is awesome but if the data isn't filter'able then back to the drawing board!
Ok after hours of Googling it seems that a lot of people have the same problem I am having and to get round it they either use
or
I'm trying to use msxsl:node-set() as I thought this namespace was part of my XSLT file but I keep getting 'prefix msxsl is not defined' any ideas how I can get it to recognise this function? This is the top of my XSLT file
Try "msxml" instead of "msxsl" ... it's an easy mistake to make - done it a thousand times myself.
... or if that doesn't work, just add the "msxsl" namespace to the list.
Notes from my wonderful wife who is (among many other talents) a fantastic xslt guru...
"the problem is he's now trying to assign a node set to a variable
but "within" the variable tags
not in the "select" attribute
he needs to have:
<xsl:variable name="xpath" select="blah blah blah"/>
<xsl:variable name="searchResults" select="umbraco.library:GetXmlNodeByXPath($xpath)"/>
and it'll work just fine
one variable for the xpath
one variable for the nodeset
but WHENEVER there's a nodeset, it must always be in a "select" bit
NEVER within the variable
or it turns into a string
and that's a nuisance
well, it can be done
you just need some c# to stitch it back together again"
Well, there you have it.
DM me if you need help working it up to a full solution.
cheers,
doug.
I'm going to try this in a minute :) ... Top man (And Wife .. lol)
In case anyone else is wanting to do this, I have blogged the solution here
http://www.blogfodder.co.uk/post/Building-Up-A-String-XPath-Statement-In-XSLT.aspx
is working on a reply...