Re: [xsl] simple XPath question

Subject: Re: [xsl] simple XPath question
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Mon, 02 Jul 2001 18:45:32 +0100
Hi Chris,

Yours is a problem that nicely demonstrates why position() can be tricky to use except in very clearly controlled situations. (It's sometimes recommended as an alternative to more expensive operations, but it has its own traps to watch out for.)

The function returns the "context position" of the node being processed. This is tricky because the context position is the position of the node among the nodes it is picked up with, when it's picked up, i.e. the "current node list". And what, exactly, the current node list is, is sometimes a bit hard to see -- especially when things like whitespace-only nodes (which are easy not to see) get involved.

At 09:47 PM 7/2/01, you wrote:
I am trying to work through an example in Khun Yee Fung's XSLT book.  It is
not giving me the solution he claims it should, but I do not understand why
not.

Here is the sample XML:
[snipped]
And here is the stylesheet:
[more snipped]
<xsl:template match='warehouse'>
  <storage>
    <xsl:apply-templates select='item/country'/>
  </storage>
</xsl:template>

<xsl:template match='country'>
  <xsl:copy-of select='.'/>
</xsl:template>

<xsl:template match='country[1]'>
  <first-country>
    <xsl:copy-of select='.'/>
  </first-country>
</xsl:template>

</xsl:stylesheet>

The output I am getting [using Saxon] is:
<?xml version="1.0" encoding="utf-8"?>
<storage>
   <first-country>
      <country>US</country>
   </first-country>
   <first-country>
      <country>Canada</country>
   </first-country>
</storage>

i.e., the first-country template is getting matched both times, even though
the XPath expression uses country[1].

This is correct behavior. Each time the country element in your source is selected, it is the first country element among country element children of its parent. So both of them match the expression "child::country[position()=1]" (which is the unabbreviated form of the expression "country[1]").


  What seems strange to me is that when
I include the line <xsl:copy-of select='position()'/> at the beginning of
the template matching country[1], I get a 1 and a 2.

This is also correct (though perhaps a bit arguable). Both 'country' elements were selected by the <xsl:apply-templates select="item/country"/> instruction in the template matching the 'warehouse' element. This is short for select="child::item/child::country". Since each is the first 'country' child of its parent 'item', both get position()=1. (The reason I say it's arguable is that I can see someone saying "but isn't the current node list the list of country children of item children"? But I'm not quite willing to dig into the spec this second and hash out why it's not.)


I believe I am supposed to get:
<storage>
<first-country>
  <country>US</country>
</first-country>
<country>Canada</country>
</storage>

Am I doing something wrong, or is the example in Fung's book (Chapter 6, p.
149) wrong?  How should the stylesheet be structured to get the intended
output?

I can't speak to Fung's book since I don't have a copy. :-(


But a more robust match to do what you want would be

<xsl:template match="country[not(preceding::country)]" >

or, if you're concerned about performance (since this match will be slow on large documents), you can try

<xsl:template match="country[not(preceding::country)[1]]" >

which will allow some processors to optimize the test somewhat.

Hope that helps,
Wendell

======================================================================

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