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.
badtz7229Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

zc2Commented:
I could suggest two options.
 If you use the MSXML processor, you could try to utilize the  msxsl:node-set() function to access the node copied to the variable:
  <xsl:variable name="Miscellaneous" >
    <xsl:choose>
    <xsl:when test="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[Fee/@cpn=$cpnNumb]">
      <xsl:copy-of select="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[Fee/@cpn=$cpnNumb]" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[1]" />
    </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  
    <xsl:attribute name="Sub">
      <xsl:value-of select="msxsl:node-set($Miscellaneous)/Misc/OptSvc/@reason"/>
    </xsl:attribute>

Open in new window

Note, I replaced the value-of with copy-of in the variable declaration.

The second option is to avoid storing a node in a variable.

In this particular case you could store in the variable the reason string value, not the node:
  <xsl:variable name="MiscellaneousReason" >
    <xsl:choose>
    <xsl:when test="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[Fee/@cpn=$cpnNumb]">
      <xsl:value-of select="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc[Fee/@cpn=$cpnNumb]/OptSvc/@reason" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$TktDocRS/Details[1]/EMD[@number=$Doc]/Misc/OptSvc/@reason" />
    </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  
  <RESULT>
    <xsl:attribute name="Sub">
      <xsl:value-of select="$MiscellaneousReason"/>
    </xsl:attribute>

Open in new window

0
Geert BormansInformation ArchitectCommented:
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

0
zc2Commented:
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.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

badtz7229Author Commented:
@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>
0
zc2Commented:
Yes, you need to use that msxsl:node-set() function. Note, that the nodeset is actually a parent of the Misc element not the Misc itself.

<xsl:attribute name="Code">
      <xsl:value-of select="msxsl:node-set($Miscellaneous)/Misc/Opt/@reason"/>
</xsl:attribute>

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Geert BormansInformation ArchitectCommented:
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
0
badtz7229Author Commented:
Zc2 yes that worked
0
zc2Commented:
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.
0
badtz7229Author Commented:
thanks
0
Geert BormansInformation ArchitectCommented:
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
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
CSS

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.