views:

71

answers:

2

Hello Stack Overflow,

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>
+1  A: 

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]" /> 
Alejandro
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
@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).
Alejandro
Yep this works too.
Marko
+4  A: 

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
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
I changed not($vRealSource) to not($source) and it now works. Thanks a lot, much appreciated.
Marko