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?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
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

Gertone (Geert Bormans)Information 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

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.
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook 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>
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

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
Gertone (Geert Bormans)Information 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
badtz7229Author Commented:
Zc2 yes that worked
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.
badtz7229Author Commented:
thanks
Gertone (Geert Bormans)Information 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
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.