Copied to clipboard

Flag this post as spam?

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


  • Soeren Sprogoe 575 posts 259 karma points
    Apr 14, 2010 @ 16:45
    Soeren Sprogoe
    0

    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:

    <xsl:variable name="dynQuery" select="$currentPage/data[@alias='dynquery']"/>

    <xsl:for-each select="concat('$currentPage',$dynQuery)">
    <xsl:value-of select="."/>
    </xsl:for-each>

    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.

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Apr 14, 2010 @ 18:26
    Chriztian Steinmeier
    2

    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

  • Soeren Sprogoe 575 posts 259 karma points
    Apr 14, 2010 @ 18:49
    Soeren Sprogoe
    0

    @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

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Apr 14, 2010 @ 20:17
    Chriztian Steinmeier
    0

    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

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Apr 14, 2010 @ 21:29
    Morten Bock
    0

    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:

    <!DOCTYPE xsl:stylesheet [
        <!ENTITY nbsp "&#x00A0;">
        <!ENTITY hidden "umbraco:library:SomeMethod()">
    ]>
  • Soeren Sprogoe 575 posts 259 karma points
    Apr 14, 2010 @ 21:59
    Soeren Sprogoe
    0

    @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

  • Chriztian Steinmeier 2800 posts 8790 karma points MVP 8x admin c-trib
    Apr 14, 2010 @ 23:10
    Chriztian Steinmeier
    0

    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:

    <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.

    (I'll provide an example if it is) ?

    /Chriztian

     

     

     

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Apr 14, 2010 @ 23:14
    Lee Kelleher
    1

    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:

    <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?

    Cheers, Lee.

  • Soeren Sprogoe 575 posts 259 karma points
    Apr 19, 2010 @ 16:16
    Soeren Sprogoe
    2

    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:

    public static XPathNodeIterator GetXmlDocumentByXPath(string Filename, bool Relative, string XPath)
    {
    XmlDocument xmlDoc = new XmlDocument();
    try
    {
    if (Relative)
    xmlDoc.Load(HttpContext.Current.Server.MapPath(Filename));
    else
    xmlDoc.Load(Filename);
    }
    catch (Exception err)
    {
    xmlDoc.LoadXml(string.Format("<error path=\"{0}\" relative=\"{1}\">{2}</error>",
    HttpContext.Current.Server.HtmlEncode(Filename), Relative, err));
    }
    XPathNavigator xp = xmlDoc.CreateNavigator();
    return xp.Select(XPath);
    }

    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

     

  • dillorscroft 198 posts 192 karma points
    Apr 28, 2010 @ 22:16
    dillorscroft
    1

    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

     

     

     

Please Sign in or register to post replies

Write your reply to:

Draft