xsl-list
[Top] [All Lists]

Re: Using variables to determine nodesets with conditions

2003-09-23 10:33:43
Hi Paulo,

Thanks, Jeni! That's EXACTLY what I was looking for!

Just so others here know what you're talking about - offlist, in reply
to more details to you, we had the exchange:

I get an $id passed into the XSL stylesheet by the XSL processor,
and for each $id the template uses a different condition to
generate the result tree. I could do it like this,

<xsl:choose>
        <xsl:if test="$id = '1'">
                <xsl:for-each select="PEOPLE/PERSON[NAME != 'Carlos']">
                <xsl:sort select="NAME">
                        <xsl:call-template name=""/>
                <xsl:for-each>
        </xsl:if>
        <xsl:if test="$id = '2'">
                <xsl:for-each select="PEOPLE/PERSON[NAME != 'Maria' and 
SURNAME =
'Perez']">
                <xsl:sort select="NAME">
                        <xsl:call-template name=""/>
                <xsl:for-each>
        </xsl:if>
        ...
</xsl:choose>

You could do something like:

  <xsl:for-each
    select="PEOPLE/PERSON[($id = 1 and NAME != 'Carlos') or
                          ($id = 2 and NAME != 'Maria' and
                                       SURNAME = 'Perez') or
                          ...]">
    <xsl:sort select="NAME" />
    <xsl:call-template name="" />
  </xsl:for-each>

If $id = 1 then the PERSON elements that will be selected are those
whose NAME child doesn't have the value 'Carlos'; if $id = 2 then
the PERSON elements that will be selected are those whose NAME child
doesn't have the value 'Maria' and whose SURNAME child has the value
'Perez' and so on.

[Personally, I'd apply templates to those PERSON elements rather than
iterating over them with <xsl:for-each> and then calling a template on
each one, but that's just a matter of style.]

...

The thing is, the solution has created another problem, since I was
using the same concept as before to determine sorting criteria in
xsl:sort :

<xsl:sort select="*[local-name() = $criteria]"/>

It does work if I have $criteria = 'NAME', but not if $criteria =
'NAME/MIDDLENAME'. Is there a way of getting around this, or should
I better change my XMLs to have all nodes used as sort keys on the
same level?

You can use a similar kind of trick here:

  <xsl:sort select="NAME[$criteria = 'NAME'] |
                    NAME/MIDDLENAME[$criteria = 'NAME/MIDDLENAME'] |
                    ..." />

This selects the <NAME> element if the $criteria variable has the
value 'NAME', the <MIDDLENAME> element if the $criteria variable has
the value 'NAME/MIDDLENAME' and so on.

This approach (essentially choosing which node to select based on the
$criteria variable) is somewhat easier/more obvious in XPath 2.0,
where you can use:

  <xsl:sort select="if ($criteria = 'NAME') then
                      NAME
                    else if ($criteria = 'NAME/MIDDLENAME') then
                      NAME/MIDDLENAME
                    ..." />

If you want to allow complete flexibility in your $criteria variable,
then there are two routes open to you. One is to use an dyn:evaluate()
extension function (as in EXSLT):

  <xsl:sort select="dyn:evaluate($criteria)" />

Some processors support such a function, so it's worth looking at the
documentation of the processor you're using to see if it does.

Another route is to generate the stylesheet that you use dynamically,
so you actually generate the element:

  <xsl:sort select="NAME/MIDDLENAME" />

when the $criteria variable has the value 'NAME/MIDDLENAME'. If you
want to pursue that route let us know and we'll be able to offer you
more advice.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


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