Hi John,
At 03:39 PM 10/21/2004, you wrote:
Sorry to trouble the list with this one which seems so simple and yet
somehow I am banging my head against the wall for hours and I can't even
think what to search for. The worst part is I think I've done this before...
How do I store a reference to a node in a variable or what am I doing
wrong? Here is what I have (maybe oversimplified) :
<xsl:variable name="me">
<xsl:choose>
<xsl:when test="<some condition>">
<xsl:copy-of select=".." />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:variable> <xsl:call-template name="<some template>">
<xsl:with-param name="myid" select="$me/@id" />
</xsl:call-template>
The with-param is always throwing an error, expression should result in a
node-set.
You are running up against a restriction in the design of XSLT 1.0, which
in keeping with its philosophy of declarative, "side-effect-free"
processing, does not want to let you process the results of your own
transformation. (XSLT 2.0 doesn't have this restriction.)
Accordingly, your copy-of instructions are not creating node sets, but
rather a data object called a "result tree fragment", which you can copy
out into your result tree, and which you can operate on as a string, but
which you cannot traverse, query into, or process as a node set.
This introduces an important distinction between
<xsl:variable name="me" select="/set/node"/>
and
<xsl:variable name="me">
<xsl:copy-of select="/set/node"/>
</xsl:variable>
In the first case, $me is an honest node set, and you can do anything with
it you can do on any node set, such as apply-templates to it. But in the
second case, it's a result tree fragment, and you can't.
In order to apply this in your conditional case, you need to express the
conditional directly in the XPath. So:
<xsl:variable name="condition" select="boolean( ... your conditional ...)"/>
<xsl:variable name="me"
select="self::node()[$condition] | parent::node()[not($condition)]"/>
(You could of course avoid using that $condition variable by putting the
conditional expression itself into those predicates: here, I include it for
clarity and to force its value to a boolean, which it may be in any case,
in the event.)
If I add msxsl:node-set around my selects in the variable definition I get
cannot convert result tree fragment to node-set.
In more complex cases, you can convert the RTF into a node set using a
node-set() function, but you wouldn't do it in the way you suggest (on a
select in a copy-of instruction, which by definition creates a *copy* of a
node set and does not bind the node set itself to the variable), but rather
on the variable itself:
<xsl:with-param name="myid" select="exsl:node-set($me)/@id" />
... though note that since a result-tree-fragment has a little root of its
own, this may actually have to be exsl:node-set($me)/*/@id or some such.
Alternatively, is there any way to explicitly set the context node without
using for-each?
Sure: you can apply templates to the node you want to be the context node.
:-> But that won't solve your problem: it has to be a node before it can be
a context node.
I hope this helps,
Wendell
======================================================================
Wendell Piez
mailto:wapiez(_at_)mulberrytech(_dot_)com
Mulberry Technologies, Inc. http://www.mulberrytech.com
17 West Jefferson Street Direct Phone: 301/315-9635
Suite 207 Phone: 301/315-9631
Rockville, MD 20850 Fax: 301/315-8285
----------------------------------------------------------------------
Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================