Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT 1.0 - conditional node assignment

Tags:

xslt

xpath

using pure XSLT 1.0, how can I conditionally assign the node. I am trying something like this but it's not working.

<xsl:variable name="topcall" select="//topcall"/>
<xsl:variable name="focusedcall" select="//focusedcall" />

<xsl:variable name="firstcall" select="$topcall | $focusedcall"/>

For variable firstcall, I am doing the conditional node selection. if there is a topcall then assign it to firstcall, othersie assign firstcall to the focusedcall.

like image 756
rpg Avatar asked Nov 15 '11 18:11

rpg


1 Answers

This should work:

<xsl:variable name="firstcall" select="$topcall[$topcall] |
                                       $focusedcall[not($topcall)]" />

In other words, select $topcall if $topcall nodeset is non-empty; $focusedcall if $topcall nodeset is empty.

Re-Update regarding "it can be 5-6 nodes":

Given that there may be 5-6 alternatives, i.e. 3-4 more besides $topcall and $focusedcall...

The easiest solution is to use <xsl:choose>:

<xsl:variable name="firstcall">
  <xsl:choose>
    <xsl:when test="$topcall">    <xsl:copy-of select="$topcall" /></xsl:when>
    <xsl:when test="$focusedcall"><xsl:copy-of select="$focusedcall" /></xsl:when>
    <xsl:when test="$thiscall">   <xsl:copy-of select="$thiscall" /></xsl:when>
    <xsl:otherwise>               <xsl:copy-of select="$thatcall" /></xsl:otherwise>
  </xsl:choose>
</xsl:variable>

However, in XSLT 1.0, this will convert the output of the chosen result to a result tree fragment (RTF: basically, a frozen XML subtree). After that, you won't be able to use any significant XPath expressions on $firstcall to select things from it. If you need to do XPath selections on $firstcall later, e.g. select="$firstcall[1]", you then have a few options...

  1. Put those selections into the <xsl:when> or <xsl:otherwise> so that they happen before the data gets converted to an RTF. Or,
  2. Consider the node-set() extension, which converts an RTF to a nodeset, so you can do normal XPath selections from it. This extension is available in most XSLT processors but not all. Or,
  3. Consider using XSLT 2.0, where RTFs are not an issue at all. In fact, in XPath 2.0 you can put normal if/then/else conditionals inside the XPath expression if you want to.
  4. Implement it in XPath 1.0, using nested predicates like

:

select="$topcall[$topcall] |
        ($focusedcall[$focusedcall] | $thiscall[not($focusedcall)])[not($topcall)]"

and keep on nesting as deep as necessary. In other words, here I took the XPath expression for 2 alternatives above, and replaced $focusedcall with

($focusedcall[$focusedcall] | $thiscall[not($focusedcall)])

The next iteration, you would replace $thiscall with

($thiscall[$thiscall] | $thatcall[not($thiscall)])

etc.

Of course this becomes hard to read, and error-prone, so I would not choose this option unless the others aren't feasible.

like image 57
LarsH Avatar answered Sep 18 '22 22:09

LarsH