Fx. have a query stored within a dictionary item or node property, pull it out in an XSLT macro, fire it off against Umbraco and have it display the result?
The library method GetXmlNodeByXPath() lets you do something like that - though you can't use $currentPage in the path you send to it, you can construct an XPath like this to get the same functionality: concat('/root//node[@id = ', $currentPage/@id, ']/', $dynQuery)
The object you get back, will definitely implement some interface that lets you perform XPath selections on it. For instance, in the good old days (of ASP fame) we'd have the IXMLDOMNode interface that gave you .selectSingleNode() and .selectNodes() to perform XPaths with...
But hey, this is C# so you'll probably have to create some kind of "navigator" object from it first :-)
@Chriztian: I'm not doing this in C#, so far it is done in pure XSLT and Umbraco's own extensions.
But judging from a lot of Googling around, and especially after discovering Lee's post on the subject, I'm guessing the only way to accomplish this, is to write my own little extension (or do a bit of inline coding).
@Morten: Thank you for pimpin' my article :-) All the entity trick does though, is provide an alias for the brain, to something that already exists, so it won't help us get the functionality Søren is missing... but, I think I understand it better now.
It depends a lot on how dynamic you need this to be.
Let's say you're loading a document that looks like this:
<doc>
<page name="home">
<star rating="****" />
<!-- more -->
</page>
<page name="gnome">
<star rating="**" />
<!-- more -->
</page>
</doc>
You get it into the variable $doc - and now you want to apply templates to either page or star elements, depending on the value in $dynQuery.
- If this is what you need, you might be able to use the xsl:key instruction and the key() function for getting what you want.
In a nutshell, the problem here - specifically with XSLT 1.0 - is that you can not evaluate a string as an XPath query.
The way around this, as it has been suggested here is to use an XSLT extension to apply the string (as an XPath query) against an XML DOM object. (As Chriztian says above).
There is an eXSLT function called dyn:evaluate that would be ideal for this...
... but alas, it's not implemented in the EXSLT.NET (included in the umbraco.dll). :-(
The code snippet from (other) Lee's blog post (or should I say Doug's code?) will work for you:
<msxml:script language="C#" implements-prefix="ps">
<![CDATA[
public string evaluateXpath(XPathNodeIterator nodes, string xpath){
/* this is intended for a SINGLE node to be passed in, although the type is XPathNodeIterator; if multiple
nodes are passed in, only the first one will be evaluated */
try{
while (nodes.MoveNext()){
XPathNavigator n = nodes.Current as XPathNavigator;
return n.Evaluate(xpath).ToString();
}
}catch{
return null;
}
return null;
}
]]>
</msxml:script>
Wonder if it's worth developing a library of community contrib methods for things like this?
Based on Lee's/Doug's original post, I realised that it couldn't be done with pure XSLT. But instead of writing an inline function like Lee suggest, I went another way:
First of all, I've already got my own xslt extension for the project, so there is no point for me to using inline code in my particular case.
Then I though about taking a peek at the umbraco source, more specifically umbraco.library:GetXmlDocument(). Turns out this function almost already does all the work, so I simply copied it over to my own xslt extension and did a minor tweak to it. Here's the code:
Basically I just changed the name of the function, added the parameter XPath, and changed the return value to selecting the XPath instead of just "/" as it is in the original code.
Dynamic XPath query
Hi everyone,
is it possible to make a dynamic XPath Query?
Fx. have a query stored within a dictionary item or node property, pull it out in an XSLT macro, fire it off against Umbraco and have it display the result?
Or something like this:
Ofcourse concat() doesn't work, but hopefully you get what I'm after. My exact scenario is a bit too complex to explain here :-)
/Soeren S.
Hi Søren,
The library method GetXmlNodeByXPath() lets you do something like that - though you can't use $currentPage in the path you send to it, you can construct an XPath like this to get the same functionality: concat('/root//node[@id = ', $currentPage/@id, ']/', $dynQuery)
Hope it translates well to the real scenario :-)
/Chriztian
@Chriztian: Actually my scenario is not for quering Umbraco, but for an external file via the umbraco.library:GetXmlDocument().
Sorry for not mentioning that, just thought I would use Umbraco for a simpler example :-)
Other than that I think you're right. GetXmlNodeByXPath() could be used for such a thing.
/SoerenS
OK - but then you it's probably even easier.
The object you get back, will definitely implement some interface that lets you perform XPath selections on it. For instance, in the good old days (of ASP fame) we'd have the IXMLDOMNode interface that gave you .selectSingleNode() and .selectNodes() to perform XPaths with...
But hey, this is C# so you'll probably have to create some kind of "navigator" object from it first :-)
/Chriztian
Would it maybe be possible to do it with the entities trick Christian?
http://pimpmyxslt.com/articles/entity-tricks-part1/
Is it possible to define something like that:
@Chriztian: I'm not doing this in C#, so far it is done in pure XSLT and Umbraco's own extensions.
But judging from a lot of Googling around, and especially after discovering Lee's post on the subject, I'm guessing the only way to accomplish this, is to write my own little extension (or do a bit of inline coding).
/SoerenS
The plot thickens...
@Morten: Thank you for pimpin' my article :-) All the entity trick does though, is provide an alias for the brain, to something that already exists, so it won't help us get the functionality Søren is missing... but, I think I understand it better now.
It depends a lot on how dynamic you need this to be.
Let's say you're loading a document that looks like this:
You get it into the variable $doc - and now you want to apply templates to either page or star elements, depending on the value in $dynQuery.
- If this is what you need, you might be able to use the xsl:key instruction and the key() function for getting what you want.
(I'll provide an example if it is) ?
/Chriztian
In a nutshell, the problem here - specifically with XSLT 1.0 - is that you can not evaluate a string as an XPath query.
The way around this, as it has been suggested here is to use an XSLT extension to apply the string (as an XPath query) against an XML DOM object. (As Chriztian says above).
There is an eXSLT function called dyn:evaluate that would be ideal for this...
http://www.exslt.org/dyn/functions/evaluate/index.html
... but alas, it's not implemented in the EXSLT.NET (included in the umbraco.dll). :-(
The code snippet from (other) Lee's blog post (or should I say Doug's code?) will work for you:
Wonder if it's worth developing a library of community contrib methods for things like this?
Cheers, Lee.
Thanks for all your help with this, guys!
Based on Lee's/Doug's original post, I realised that it couldn't be done with pure XSLT. But instead of writing an inline function like Lee suggest, I went another way:
First of all, I've already got my own xslt extension for the project, so there is no point for me to using inline code in my particular case.
Then I though about taking a peek at the umbraco source, more specifically umbraco.library:GetXmlDocument(). Turns out this function almost already does all the work, so I simply copied it over to my own xslt extension and did a minor tweak to it. Here's the code:
Basically I just changed the name of the function, added the parameter XPath, and changed the return value to selecting the XPath instead of just "/" as it is in the original code.
Karma goes to Lee for his blog post.
/SoerenS
I have a solution for complete dynamic XPathQuery that takes a string and returns an xpathnodeiteraor object which is just standard umbraco schema.
I'll package it up anyone wants it?
DC
is working on a reply...