Link to home
Start Free TrialLog in
Avatar of tesmc
tesmcFlag for United States of America

asked on

XSL: copy node into a variable

How can I store a node into a variable.

I have the following:


<xsl:variable name="Miscellaneous" >
  <xsl:choose>
	<xsl:when test="not ($TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[Fee/@cpn=$cpnNumb])">
	  <xsl:value-of select="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc" />
	</xsl:when>
	<xsl:otherwise>
	  <xsl:value-of select="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[Fee/@cpn=$cpnNumb]" />
	</xsl:otherwise>
  </xsl:choose>
</xsl:variable>


	<xsl:attribute name="Sub">
	  <xsl:value-of select="$Miscellaneous/OptSvc/@reason"/>
	</xsl:attribute>

Open in new window

     
However, Miscellaneous returns a string and not node, so when I try to access it later on it fails.
SOLUTION
Avatar of zc2
zc2
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
If you allow me to step in...
Though not really needed in the question example, the generic question here is "How can I store a node into a variable"

The generic answer to your question is
- when XSLT1 use node-set(), but that binds your XSLT to a processor, most XSLT1 processors implement the node-set() extension function, most processors do so in the exslt namespace, microsoft is an exception, they implement the function in their own namespace, as zc2 showed you
- when XSLT2 there is no issue, you can simply stuff the nodes in the variable (use copy-of, not value-of) and you can use XPath on the variable sequence

However, the first thing to check is whether you need to use the choose at all. Because when you bind a node(set) to a variable using the select attribute... it simply remains a nodeset. So your first instinct should always be to try to use the select attribute of xsl:variable

In this example here is what I would do in both XSLT1 and XSLT2
   <xsl:variable name="Miscellaneous" select="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[not(Fee[@cpn=$cpnNumb])] | $TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[Fee/@cpn=$cpnNumb]"/>

now $Miscellaneous is bound to the exact Misc element you want and you can XPath on it

Here is what you nee to know
xsl:variable
- when you use @select, the variable is bound to the nodeset from the XPath in the @select
- when you use a value-of inside the variable, you create a text node with a string inside (as a result tree fragment in XSLT1, as a sequence in XSLT2)
- when you use copy-of inside the variable, you create a result tree fragment in XSLT1 (you can not access RTF in XSLT1 unless using the node-set() function,) or a sequence in XSLT2

And now, the important bit is: always try to use @select as the first alternative. It gives you the most flexibility and it is an important bit more performant in all XSLT processors

Geert, I agree that one should always try to use @select first. But in this case the xpath you suggested does not return an expected result. At least as I understood, it was asked that the variable to be filled with the specific Misc element (if it contains the Fee with matched @cpn), or if there is not such, then take the first Misc.  
Your xpath returns all Misc nodes, and the variable just stores the first one.
Avatar of tesmc

ASKER

@zc2-:
ur solution of using copy-of worked. but now that i want to access $Miscellaneous I receive the following

"To use a result tree fragment in a path expression, first convert it to a node-set using the msxsl:node-set() function."

i'm using it as follows:

                <xsl:attribute name="Code">
                  <xsl:value-of select="$Miscellaneous/Opt/@reason"/>
                </xsl:attribute>
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
well zc2,
"Geert, I agree that one should always try to use @select first. But in this case the xpath you suggested does not return an expected result"

It is not at all clear from the original question (the variable uses value-of and there is no source XML as an example) whether the question requires a single Misc as a return node or all... you added a "[1]" in your example, I did not see that "[1]" in the original variable.

So when you speak about "expected result" you mean "the result as expected by zc2"
You know very well that putting a "[1]" at the right place in my XPath expression will return exactly one node, if that is the requirement.
But no point in making assumptions what the expected node should have been, unless the Original Poster steps in to clarify

The point I wanted to make is, evaluate first if using @select is an option.
And if you look at my XPath suggestion, you see that I nicely worked the entire choose in a simple union...
in other words, whether Badtz needs one node or the entire nodeset or anything in between,
you can simply avoid binding your stylesheet to a single processor in this task,
by having an Xpath very similar to my suggestion and most likely not more complex
Avatar of tesmc

ASKER

Zc2 yes that worked
Geert,
Ok, can we assume that a single Misc element is to be stored because the OP states in his question: "store a node into a variable"?

And, like I said, I completely agree that the node-set() is the last resort to approach.
Avatar of tesmc

ASKER

thanks
Regardless of which suggestion you have accepted... I hope you found some value in the notes I made.
From the general point of view of getting a grip on XSLT development, they do make a lot of sense