Re: [xsl] Long time no axes/document question

Subject: Re: [xsl] Long time no axes/document question
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Thu, 20 Jun 2002 17:01:57 +0100
Hi Richard,

> Right then the scenario is that I want to find out if a preceding
> sibling of mine has an item in another document with a attribute
> comparison between the two. What I have so far is...
>
> <xsl:variable name="sitedefxsl" select="document('sitedef.xsl')"/>
> <xsl:when test='not(preceding-sibling::menu[(not(@system) or
> $sitedefxsl//xsl:when[xsl:call-template[@name="url_check" or
> @name="article_system"] and
> contains(@test,concat("&apos;",translate(./@system,$UCASE,$lcase),"&apos
> ;"))]) and not(@hidden) and not(menu)])'>default.asp</xsl:when>
>
> I hope this is understandable - the bit that is messing me up is the
> ./@system because the . context is in the document not the element
> in the axes where I want it. I've done a similar thing earlier in
> the same style sheet for something not in an axes by preserving the
> conext in a variable but I can't see there is way to preserve a
> (possible) location in an axis.

This (and readability!) is a problem when you have predicates nested
inside each other. A way of pulling this out is to use an xsl:for-each
to go through the preceding-sibling menu elements one by one. That has
the advantage of allowing you to use the current node or intermediate
variables within the tests, so you can do:

  <xsl:variable name="sitedefxsl" select="document('sitedef.xsl')" />
  <xsl:variable name="whens"
    select="$sitedefxsl//xsl:when
              [xsl:call-template
                [@name = 'url_check' or @name = 'article_system']]" />
  <xsl:variable name="test">
    <xsl:for-each select="preceding-sibling::menu">
      <xsl:variable name="system"
        select='concat("&apos;",
                       translate(@system, $UCASE, $lcase),
                       "&apos;")' />
      <xsl:if test="not(@hidden) and not(menu) and
                    (not(@system) or
                     $whens[contains(@test, $system)]">true</xsl:if>
    </xsl:for-each>
  </xsl:variable>
  ...
  <xsl:when test="$test != 'true'">
    ...
  </xsl:when>
  ...

It's been suggested that XPath 2.0 enable you to set variables within
expressions to make this kind of thing easier, in which case you would
be able to do something like:

  <xsl:when test='preceding-sibling::menu[
                    $system := concat("&apos;",
                                      lower-case(@system),
                                      "&apos;");
                    not(@hidden) and not(menu) and
                    (not(@system) or
                     $whens[contains(@test, $system)]]'>
    ...
  </xsl:when>

Cheers,

Jeni

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


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


Current Thread