[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Giving values to xsl:variable by xml attribute


Subject: Re: [xsl] Giving values to xsl:variable by xml attribute
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 04 Oct 2001 11:24:51 -0400

Ofer--

You're running into trouble actually for two reasons. First, when you declare the variable

This is my static xsl tree
<xsl:variable name="values">
        <one>1</one>
        <two>2</two>
</values>

what you have assigned is not actually a node set (despite appearances), it's a Result Tree Fragment -- which is like a node set in many respects, except you can't query it.


Second, you can't construct XPath queries dynamically, so if

This is the input xml:
<x value="one"/>
.
<xsl:value-of name="$values/one"/>

This will work, but what if I want the "one" node to be determined by the
xml value?

you're stuck ... you can't write an XPath that would say (e.g.) $values/{x/@value} with {x/@value} evaluated dynamically.


So how to do what you want? You basically have three choices.

#1 is to use an extension function. Many processors have a function that can be used to turn the RTF into a node set. Then you could query it with an expression like

<xsl:value-of select="ext:node-set($values)/*[name()= x/@value]"/>

where ext:node-set is your extension function (consult your processor's documentation). The */[name()= x/@value] gets around the "dynamic XPath" problem. The extension function gets you around the problem with the Result Tree Fragment.

[note: in future versions of XSLT, it may not be necessary to use an extension function for this.]

#2 is to do essentially what you're doing, but instead of using a variable, use the document() function to query the stylesheet itself as a node tree. It's done like this:

<my:values xmlns:my="http://mynamespace-declaration-uri">
        <one>1</one>
        <two>2</two>
<my:values>

Goes in the stylesheet.

Then you can query it like so:

<xsl:value-of select="document('')/*/my:values/*[local-name()= x/@value]"/>

notice the extra step in the location path to get below the xsl:stylesheet element. (Using the local-name() function is just a precaution against namespace funkiness.)

(We need a name for this idiom. Was it Oliver Becker who first noticed it? I've heard it called 'local lookup tables' and such things, but that's neither very catchy nor very descriptive.)

(Another note: you could even avoid the my:values element by declaring a variable, as you did, and then saying

<xsl:value-of select="document('')/*/xsl:variable[@name='values']/*[local-name()= x/@value]"/>

but I think you'll agree that's a little misleading because you're not actually using the variable as a variable, you're just querying into it as a node in your stylesheet.)

Option #3 is to run your process in two steps. The first step generates the stylesheet that you run in the second step. This will get you around having to do the *[local-name()= x/@value] thing, since your XPath will be generated in step 1 and evaluated in step 2. You'll still have to use one of the other techniques to get your match. This option is probably worthwhile only if your requirements for dynamic processing get really ornate.

I hope this helps.

Regards,
Wendell




XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
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
======================================================================


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list




Current Thread
Keywords