Copied to clipboard

Flag this post as spam?

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


  • Lee 1130 posts 3088 karma points
    Dec 16, 2009 @ 11:13
    Lee
    0

    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

    <xsl:for-each select="/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius">

    But this doesn't

        <xsl:variable name="thesearch">
          <xsl:text>/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius</xsl:text>
        </xsl:variable>
    <xsl:for-each select="$thesearch">

    I don't see any difference???  I need to build up a select string so need to put it in a variable???

  • Shaun 248 posts 475 karma points
    Dec 16, 2009 @ 11:19
    Shaun
    1

    I'm equally thrown by XSLT, does this work?

    <xsl:variable name="thesearch">
    <xsl:value-of select="/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius" />
    </xsl:variable>
    <xsl:for-each select="$thesearch">
  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Dec 16, 2009 @ 11:21
    Lee Kelleher
    0

    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:

    <xsl:variable name="thesearch" select="/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius" />
    
    <xsl:for-each select="$thesearch">
    ...

    then that would work fine.

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Dec 16, 2009 @ 11:27
    Lee Kelleher
    0

    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:

    $currentPage/ancestor-or-self::node[@level=1]

    as your pseudo "root" node?

    Cheers, Lee.

  • Lee 1130 posts 3088 karma points
    Dec 16, 2009 @ 11:37
    Lee
    0

    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']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $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 :)

    Thanks again for helping chaps, appreciated

  • Lee 1130 posts 3088 karma points
    Dec 16, 2009 @ 11:53
    Lee
    0

    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?

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Dec 16, 2009 @ 11:54
    Lee Kelleher
    0

    Hi Lee,

    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']) &gt; 0 and number(data[@alias='distance']) &lt; $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']) &gt; 0 and number(data[@alias='distance']) &lt; $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. ;-)

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Dec 16, 2009 @ 12:01
    Lee Kelleher
    0

    Hi Lee,

    OK, figured it... there is an umbraco.library method called "GetXmlNodeByXPath", here's how you can use it:

    <xsl:variable name="xpathQuery">
        <xsl:text>/root//node ... </xsl:text>
    </xsl:variable>
    <xsl:for-each select="umbraco.library:GetXmlNodeByXPath($xpathQuery)"></xsl:for-each>

    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.

  • Lee 1130 posts 3088 karma points
    Dec 16, 2009 @ 12:22
    Lee
    0

    Thanks for the help Lee :)

    Unfortunately its still not working?  I have tried it like so but to no avail

          <!-- ############  Build up the select ############## -->
          <xsl:variable name="thesearch">
            <xsl:text>/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius and umbraco.library:DateGreaterThanOrEqualToday(./data [@alias='eventDate'])]</xsl:text>
          </xsl:variable>
          <!-- ############  End Select ############## -->
    <xsl:for-each select="umbraco.library:GetXmlNodeByXPath('$thesearch')">
    <xsl:for-each select="umbraco.library:GetXmlNodeByXPath($thesearch)">

    And tried your first solution?  Still it seems to only work if I actually do it like this???? 

    <xsl:for-each select="/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius and umbraco.library:DateGreaterThanOrEqualToday(./data [@alias='eventDate'])]">

    I'm a touch gobsmacked at the moment :(

  • Lee 1130 posts 3088 karma points
    Dec 16, 2009 @ 13:17
    Lee
    0

    Ahhhhhhhhhhhh ok I admit it, I just don't get XSLT... Why does this work fine and returns the correct XML

    <xsl:variable name="thesearch" 
                      select="/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius and umbraco.library:DateGreaterThanOrEqualToday(./data [@alias='eventDate'])]" />

    And this just dies??

        <xsl:variable name="thesearch">
          <xsl:value-of select="/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius and umbraco.library:DateGreaterThanOrEqualToday(./data [@alias='eventDate'])]" />
        </xsl:variable>

    What the **** is going on.. lol! 

    P.S. Anyone have a rope?

  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Dec 16, 2009 @ 13:39
    Lee Kelleher
    0

    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:

    <!-- ############  Build up the select ############## -->
    <xsl:variable name="thesearch">
        <xsl:text>/root//node[string-length(data[@alias='distance']) &gt; 0 and number(data[@alias='distance']) &lt; </xsl:text>
        <xsl:value-of select="$radius" />
        <xsl:text> and ( number(translate(data[@alias='eventDate'], '-:T', '')) &gt;= 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?
    Good luck, Lee.
  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Dec 16, 2009 @ 13:45
    Lee Kelleher
    0

    oh, another quickie... I'll leave it alone after this... try copy-of instead of value-of:

    <xsl:variable name="thesearch">
        <xsl:copy-of select="/root//node [string-length(./data [@alias = 'distance']) &gt; 0 and number(./data [@alias = 'distance']) &lt; $radius and umbraco.library:DateGreaterThanOrEqualToday(./data [@alias='eventDate'])]" />
    </xsl:variable>
  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Dec 16, 2009 @ 13:58
    Douglas Robar
    1

    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.

  • Lee 1130 posts 3088 karma points
    Dec 16, 2009 @ 14:02
    Lee
    0

    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! 

  • Lee 1130 posts 3088 karma points
    Dec 16, 2009 @ 18:19
    Lee
    0

    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

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet 
        version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:msxml="urn:schemas-microsoft-com:xslt"
        xmlns:umbraco.library="urn:umbraco.library" 
      xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" 
      xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" 
      xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" 
      xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" 
      xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" 
      xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" 
      xmlns:Locator="urn:Locator" 
        exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets Locator">
  • Lee Kelleher 4026 posts 15836 karma points MVP 13x admin c-trib
    Dec 16, 2009 @ 18:31
    Lee Kelleher
    0

    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.

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Dec 17, 2009 @ 00:23
    Douglas Robar
    1

    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.

  • Lee 1130 posts 3088 karma points
    Dec 17, 2009 @ 07:10
    Lee
    0

    I'm going to try this in a minute :) ... Top man (And Wife .. lol)

  • Lee 1130 posts 3088 karma points
    Dec 22, 2009 @ 22:10
    Lee
    0

    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

Please Sign in or register to post replies

Write your reply to:

Draft