Copied to clipboard

Flag this post as spam?

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


  • jacob phillips 130 posts 372 karma points
    Apr 11, 2014 @ 05:03
    jacob phillips
    0

    variable node selector w/GetXmlNodeById

    I have a condition where I want my macros node selector to have the option of being parameter-less. How can it be done? The parameter, "PrimaryCategory" filters on a property, like this:

    <xsl:variable name="articleNodes" select="umbraco.library:GetXmlNodeById(1092)//story[contains(concat(',',primaryCategory,','),concat(',',$PrimaryCategory,',')) and archiveDate != '' and umbraco.library:DateGreaterThan($DateNow, displayDate) and @id != $currentPage/@id]" /> 
    

    But sometimes, this macro will be used w/o a "Primary Category" like this:

    <xsl:variable name="articleNodes" select="umbraco.library:GetXmlNodeById(1092)//story[archiveDate != '' and displayDate != '' and umbraco.library:DateGreaterThan(archiveDate, $DateNow)  and umbraco.library:DateGreaterThan($DateNow, displayDate)]"/>
    

    I want to do something like this:

    <xsl:variable name="aritcleNodes">
    <xsl:choose>
    <xsl:when test="$PrimaryCategory == ''">
    <xsl:value-of select="umbraco.library:GetXmlNodeById(1092)//story[archiveDate != '' and displayDate != '' and umbraco.library:DateGreaterThan(archiveDate, $DateNow)  and umbraco.library:DateGreaterThan($DateNow, displayDate)]"" />
    </xsl:when>
    <xsl:otherwise>
    <xsl:value-of select="umbraco.library:GetXmlNodeById(1092)//story[contains(concat(',',primaryCategory,','),concat(',',$PrimaryCategory,',')) and archiveDate != '' and umbraco.library:DateGreaterThan($DateNow, displayDate) and @id != $currentPage/@id]" />
    </xsl:otherwise>
    </xsl:choose>
    </xsl:variable>
    

    But I get:

    To use a result tree fragment in a path expression, first convert it to a node-set using the msxsl:node-set() function. 
    
  • Jan Skovgaard 11280 posts 23678 karma points MVP 10x admin c-trib
    Apr 11, 2014 @ 08:37
    Jan Skovgaard
    0

    Hi Jacob

    The above does not show how you try to render your variable but when you get a message like that you usually need to write it like this

    Hope this helps.

    /Jan

  • jacob phillips 130 posts 372 karma points
    Apr 11, 2014 @ 09:50
    jacob phillips
    0

    I'm just looping on articleNodes in a for loop:

    <xsl:for-each select="$articleNodes">
    

    If I just define the articleNodes variable without the choose it works.

    Basically, the only way around this is to basically make a copy of this macro and change the one variable. Seems like a waste.

    ..Or maybe I'm just missing something.

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 7x admin c-trib
    Apr 11, 2014 @ 10:15
    Chriztian Steinmeier
    101

    Hi Jacob,

    Here's the trick to making that work - hopefully you can follow what's going on, otherwise feel free to ask about the specifics:

    <!-- Set a single reference for the root of all articles; makes it easier to port the macro -->
    <xsl:variable name="articleRoot" select="umbraco.library:GetXmlNodeById(1092)" />
    
    <!-- Get all the <story> nodes that are not the current page  -->
    <xsl:variable name="validArticleNodes" select="$articleRoot//story[not(@id = $currentPage/@id)]" />
    
    <!-- Get all nodes with $PrimaryCategory in their primaryCategory -->
    <xsl:variable name="primaryCategoryNodes" select="
        $validArticleNodes
        [contains(concat(',', primaryCategory, ','), concat(',', $PrimaryCategory, ','))]
    " />
    
    <!-- Get a bool flag for whether there is $PrimaryCategory defined -->
    <xsl:variable name="thereIsAPrimaryCategory" select="boolean(normalize-space($PrimaryCategory))" />
    
    <!-- Set a variable for either all $primaryCategoryNodes (if one is specified) or all $validArticleNodes -->
    <xsl:variable name="articleNodes" select="
        $primaryCategoryNodes[$thereIsAPrimaryCategory]
        | $validArticleNodes[not($thereIsAPrimaryCategory)]
    " />
    
    <!-- Iterate through all the selected nodes, filtered by their displayDate -->
    <xsl:for-each select="$articleNodes[umbraco.library:DateGreaterThan($DateToday, displayDate)]">
        <!-- Do something -->
    </xsl:for-each>
    

    Note that you can filter pretty much as much as you want, and that you can keep a very high level of readability just by adding a couple of intermediate variables.

    /Chriztian

  • jacob phillips 130 posts 372 karma points
    Apr 11, 2014 @ 17:51
    jacob phillips
    0

    Thanks Chriztian, this is a very interesting construct, basically $x[true]|$x[false]:

    <!-- Set a variable for either all $primaryCategoryNodes (if one is specified) or all $validArticleNodes -->
    <xsl:variable name="articleNodes" select="
        $primaryCategoryNodes[$thereIsAPrimaryCategory]
        | $validArticleNodes[not($thereIsAPrimaryCategory)]
    " />
    

    It all makes sense except for now I'm getting this error on $DateNow (you named it $DateToday above)

    This seems like such an unlikely error because I haven't changed the format of the date from before, which was just:

    <xsl:variable name="articleNodes" select="umbraco.library:GetXmlNodeById(1092)//story[archiveDate != '' and displayDate != '' and umbraco.library:DateGreaterThan($DateNow, displayDate)]"/>
    
    
    
    <!-- get the current time to compare to archive date -->
    <xsl:variable name="DateNow" select="umbraco.library:CurrentDate()" />
    
    <xsl:for-each select="$articleNodes[umbraco.library:DateGreaterThan($DateNow, displayDate)]" />
    

    Error is

    System.FormatException: String was not recognized as a valid DateTime.
    at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
    at System.DateTime.Parse(String s)
    at umbraco.library.DateGreaterThan(String firstDate, String secondDate)
    

    I feel like I shouldn't be asking this question, but I'm looking at the DateGreaterThan and am baffled as to why it is now giving me an error! Do you see it? I'm not seeing it.

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 7x admin c-trib
    Apr 12, 2014 @ 07:56
    Chriztian Steinmeier
    0

    Hi Jacob,

    When you get that error it's almost always (99% guaranteed) because there's one or more nodes with either no date property or an empty date property ("date" meaning displayDate or archiveDate in your case).

    When you do this:

    <xsl:variable name="articleNodes" select="umbraco.library:GetXmlNodeById(1092)//story[archiveDate != '' and displayDate != '' and umbraco.library:DateGreaterThan($DateNow, displayDate)]"/>
    

    - the DateGreaterThan() method will be run on all nodes - but if you do that in a separate predicate (the square brackets) it will only run if the previous predicate actually returned any nodes, e.g.:

    <xsl:variable name="articleNodes" select="umbraco.library:GetXmlNodeById(1092)//story
       [normalize-space(archiveDate) and normalize-space(displayDate)]
       [umbraco.library:DateGreaterThan($DateNow, displayDate)]"
    />
    

    (The normalize-space(), I've found, is the safest "check for not null")

    /Chriztian

  • jacob phillips 130 posts 372 karma points
    Apr 14, 2014 @ 22:12
    jacob phillips
    0

    ...I cherish these moments.

    I didn't know you could have multiple separate predicates like that (and I didn't know they were called "predicates").

    I did a little test, and indeed, if I write:

    <xsl:variable name="articleNodess" select="$articleNodes[displayDate != '' and archiveDate != '' and umbraco.library:DateGreaterThan($DateNow, displayDate)]" />
    

    I do not get the error, but if I write:

    <xsl:variable name="articleNodess" select="$articleNodes[umbraco.library:DateGreaterThan($DateNow, displayDate) and displayDate != '' and archiveDate != '' ]" />
    

    I do get it. I guess it is evaluated from left to right.

    It seems like it might be better in terms of performance then, to actually filter things out via separate predicates. As, if I understand you correctly, the single predicate is doing extra, unnecessary work:

    select="umbraco.library:GetXmlNodeById(1092)//story[archiveDate != '' and displayDate != '' and umbraco.library:DateGreaterThan($DateNow, displayDate)]
    

    Actually, I am not sure what performance thresholds exist on running XSLT against "large" cache files. But what you have said makes total sense. I'm interested because I never met anyone with a cache file of > 100 mb. That site was choking, but a current production site has 20mb cache file and growing, so it's on my mind.

    Thanks for the advice on normalize-space(); I will use that instead.

    Anyways, thank you Jan and Chriztian for your comments. I really want to express my gratitude at how fast you guys respond and share your knowledge. It really makes my life easier. I was off the grid MX'ing, hence the late response. I respect y'alls time a lot.

Please Sign in or register to post replies

Write your reply to:

Draft