Altova Mailing List Archives


Re: [xsl] Improving efficiency of an XPath expression?

From: Jeni Tennison <jeni@---------------->
To:
Date: 6/7/2002 5:00:00 AM
Hi Michael,

> Now the challenge: given the id attribute value of any one <l>, find
> an XPath expression that will efficiently select a node-set
> containing only: the <lg> that immediately precedes the one where
> the <l> concerned is found, plus the <lg> that is the parent of that
> <l> and the <lg> that immediately follows the one that is the parent
> of the <l> specified. (i.e. "L2063" as input id would return
> precisely the three <lg> elements in the example.)

Assuming that there's only one l with a particular id, try something
like:

  /example/lg[l/@id = $targetid][1]/preceding-sibling::lg[1] |
  /example/lg[l/@id = $targetid][1] |
  /example/lg[l/@id = $targetid][1]/following-sibling::lg[1]

Or, if you can, store the lg that contains the relevant l element in a
variable:

  <xsl:variable name="lg" select="/example/lg[l/@id = $targetid][1]" />
  
  ... select="$lg/preceding-sibling::lg[1] |
              $lg |
              $lg/following-sibling::lg[1]" ...

In XPath 2.0, you'd be able to use a general step instead of a
variable, and still get the benefit of only finding the relevant lg
once:

  /example/lg[l/@id = $targetid][1]
    /(preceding-sibling::lg[1] | . | following-sibling::lg[1])

You could alternatively use something closer to what you had already:

  /example/lg[following-sibling::lg[1]/l/@id = $targetid or
              l/@id = $targetid or
              preceding-sibling::lg[1]/l/@id = $targetid]

but that would mean going through all the lg elements in the document
rather than stopping at the one that contains the relevant l element.

The important things for efficiency here are:

  - avoidance of the descendant axis -- step down the lg elements
    rather than using //

  - using [1], so that the processor only has to make one step rather
    than collecting *all* the lg elements and preceding/following
    siblings

If you're doing this multiple times in the same transformation, then
setting up a key so that you can quickly find the relevant lg by the
ids of its l elements would be a good idea:

<xsl:key name="lgs" match="lg"
         use="preceding-sibling::lg[1]/l/@id |
              l/@id |
              following-sibling::lg[1]/l/@id" />

and then just use:

  key('lgs', $targetid)

Cheers,

Jeni

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


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

Disclaimer

These Archives are provided for informational purposes only and have been generated directly from the Altova mailing list archive system and are comprised of the lists set forth on www.altova.com/list/index.html. Therefore, Altova does not warrant or guarantee the accuracy, reliability, completeness, usefulness, non-infringement of intellectual property rights, or quality of any content on the Altova Mailing List Archive(s), regardless of who originates that content. You expressly understand and agree that you bear all risks associated with using or relying on that content. Altova will not be liable or responsible in any way for any content posted including, but not limited to, any errors or omissions in content, or for any losses or damage of any kind incurred as a result of the use of or reliance on any content. This disclaimer and limitation on liability is in addition to the disclaimers and limitations contained in the Website Terms of Use and elsewhere on the site.