Re: [xsl] Navigation using XPath

Subject: Re: [xsl] Navigation using XPath
From: Mike Brown <mike@xxxxxxxx>
Date: Wed, 13 Nov 2002 16:18:51 -0700 (MST)
Chitra Lalita Madhwacharyula wrote:
> Hello,
> 
> Is there anyway to navigate through the XML document using stylesheet by
> which I can do the following without explicitly specifying the node
> position like position() = 1 or position() = 2 etc. As far as I know
> only 'last()' is available which extracts the last value of the
> specified element.
> 
> 1> Go to the first element (e.g like position() = first()..) 
> 
> 2> Go to the next element after the current element (e.g position() =
> next().. )
> 
> 3> 2> Go to the previous element after the current element (e.g
> position() = previous().. )
> 
> 4> Go to the next sibling element from the current position.
> 
> I know that following-sibling axis is available but it returns all the
> following siblings and not just the next one which is not useful if I
> want to move through the nodes one by one (either forward or backward)
> and perform some operations. Similar is the problem with
> preceding-sibling or following or preceding and other similar axis

I didn't see this mentioned in the other answers to your question... The XPath
expressions that generate node-sets are just identifying a set of nodes.

It is the xsl:apply-templates, xsl:apply-imports, and xsl:for-each XSLT
instructions that cause nodes to be processed. They are processed in a certain
order: document order, normally, or reverse document order if a reverse axis
like ancestor:: was used, or whatever order was specified by xsl:sort.

So the "go to" in your tasks would be xsl:apply-templates, most likely.

When you want to process a batch of nodes all at once, like in #4 above you 
make it sound like you want to process all the children of a certain node,
you usually want to identify those children when you are processing their
parent. For example,

<doc>
  <e>hello</e>
  <e>world</e>
  <f>:-)</f>
  <e>goodbye cruel world</e>
</doc>

Given the above XML, the templates in your XSLT might look like this:

<!-- when processing a 'doc' element... -->
<xsl:template match="doc">
  <!-- make a table row -->
  <tr>
    <!-- process every element child, using the best matching template for each one -->
    <xsl:apply-templates select="*"/>
  </tr>
</xsl:template>

<!-- when processing an 'e' element... -->
<xsl:template match="e">
  <td>
    <xsl:value-of select="."/>
  </td>
</xsl:template>

<!-- when processing an 'f' element... -->
<xsl:template match="f">
  <td>
    <xsl:text>*grin*</xsl:text>
  </td>
</xsl:template>


This would produce

<tr>
  <td>hello</td>
  <td>world</td>
  <td>*grin*</td>
  <td>goodbye cruel world</td>
</tr>

So you see, in this example, you let the XSLT processor go from sibling to
sibling among the children of the 'doc' element. It does not require using
following-sibling::*[1] in the templates that matched 'e' and 'f'. Does this
make sense?

You can even use this approach to process some nodes conditionally.
Like if you want any 'e' element that is the following sibling of an 'f' 
element to be ignored, you could just add

<xsl:template match="e[local-name(preceding-sibling::*[1])='f']" />

So you can use this approach as long as the conditions for processing the next 
node can be expressed in XPath.

   - Mike
____________________________________________________________________________
  mike j. brown                   |  xml/xslt: http://skew.org/xml/
  denver/boulder, colorado, usa   |  resume: http://skew.org/~mike/resume/


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


Current Thread