7

I'm working on an Umbraco XSL Stylesheet and I am pretty stuck.

Basically, I have a parameter that I test and use it's value if it's present, otherwise I use the default parameter $currentPage.

Here are the parameters

<xsl:param name="source" select="/macro/sourceId" />
<xsl:param name="currentPage" />

Here's the variable

<xsl:variable name="current">
    <xsl:choose>
        <xsl:when test="$source &gt; 0">
            <xsl:copy-of select="umbraco.library:GetXmlNodeById($source)" />
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="$currentPage" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

And here's where I use it

<xsl:for-each select="msxml:node-set($source)/ancestor-or-self::* [@isDoc and @level=$level]/* [@isDoc and string(umbracoNaviHide) != '1']">
... code here ...
</xsl:for-each>


In a nutshell

This works

<xsl:variable name="source" select="$currentPage" />

This doesn't

<xsl:variable name="source">
  <xsl:copy-of select="$currentPage" /> <!-- Have tried using <xsl:value-of /> as well -->
</xsl:variable>

So how do you copy a variable without using the select="" attribute.

UPDATE: I've tried using another approach (see below) but I get a variable out of scope exception.

<xsl:choose>
    <xsl:when test="$source &gt; 0">
        <xsl:variable name="current" select="umbraco.library:GetXmlNodeById($source)" />
    </xsl:when>
    <xsl:otherwise>
        <xsl:variable name="current" select="$currentPage" />
    </xsl:otherwise>
</xsl:choose>
Marko
  • 71,361
  • 28
  • 124
  • 158
  • XSLT1 or 2? Where is $currentPage defined? What is its type? – Jim Garrison Sep 30 '10 at 21:16
  • Hi @Jim, it's XSLT 1.0 (Umbraco) and $currentPage is a built in parameter that contains a node-set of the current page and it's children. – Marko Sep 30 '10 at 21:25
  • All I'm trying to do @Jim, is have a different value for `$source` based on a test. – Marko Sep 30 '10 at 21:28
  • can you explain what behavior you are seeing that does not match what you expect? "This doesn't work" is not sufficient. – Jim Garrison Sep 30 '10 at 21:33
  • 1
    @Jim, what part of the question do you not understand? I have a parameter called $currentPage which contains a node-set. When I try to copy the parameter using ``, I get the expected output (the node-set). When I try and copy the parameter using `` or `` within a ``, I get text rather than the expected XML output. – Marko Sep 30 '10 at 21:45
  • Sorry for an error in my comment above `` is actually `` – Marko Sep 30 '10 at 21:52
  • Good question (+1). See my answer for a one-liner XPath expression that you can use to define the variable. :) – Dimitre Novatchev Sep 30 '10 at 23:02

2 Answers2

6

Generally, this expression selects one of two nodesets, based on whether a given condition is true() or false():

$ns1[$cond] | $ns2[not($cond)]

In your case this translates to:

    umbraco.library:GetXmlNodeById($source) 
|
    $currentPage[not(umbraco.library:GetXmlNodeById($source))]

The complete <xsl:variable> definition is:

<xsl:variable name="vCurrent" select=
"        umbraco.library:GetXmlNodeById($source) 
    |
        $currentPage[not(umbraco.library:GetXmlNodeById($source))]
"/>

This can be written in a more compact way:

<xsl:variable name="vRealSource" select="umbraco.library:GetXmlNodeById($source)"/>

<xsl:variable name="vCurrent" select=
    "$vRealSource| $currentPage[not($vRealSource)]"/>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • Hmm I can't get that to work, it doesn't output anything. What exactly does not() do in this case? Does it check for an empty string or something else? – Marko Oct 01 '10 at 00:17
  • I changed not($vRealSource) to not($source) and it now works. Thanks a lot, much appreciated. – Marko Oct 01 '10 at 00:38
2

Whenever you declare a variable in XSLT 1.0 without @select, but with some content template, the variable type will be of Result Tree Fragment. The variable holds the root node of this tree fragment.

So, with this:

<xsl:variable name="source"> 
  <xsl:copy-of select="$currentPage" />
</xsl:variable> 

You are declaring $source as the root of a RTF containing the copy of the nodes (self and descendants) in $currentPage node set.

You can't use / step operator with RTF. That's why you are ussing node-set extension function.

But, when you say:

node-set($source)/ancestor-or-self::*

This will be evaluate to an empty node set, because a root node hasn't ancestors an it's not an element.

EDIT: If you have two node sets, and you want to declare a variable with the content of one of the two node sets depending on some condition, you could use:

<xsl:variable name="current" 
              select="umbraco.library:GetXmlNodeById($source)[$source > 0]
                      |$currentPage[0 >= $source]" /> 
  • Thanks @Alejandro, what would you suggest I do in this scenario? I'm basically attempting to have a different source based on a test. $currentPage works fine by itself and when using @select. – Marko Sep 30 '10 at 21:51
  • @Marko Ivanovski: See my edit for a solution. Do note that conditions should be mutal exclusive and take care about context (this two are context "free" because of variable reference). –  Sep 30 '10 at 22:47