Re: Filtering the nodes passed to a template...

Subject: Re: Filtering the nodes passed to a template...
From: Mike Brown <mike@xxxxxxxx>
Date: Thu, 30 Mar 2000 01:07:50 -0700 (MST)
> <report>
> <payments>
> 	<payment id="..."/>
> 	<payment id="..."/>
> </payments>
> <paymentTypes>
> 	<paymentType paymentTypeRef="...">
> 	<paymentType paymentTypeRef="...">

I assume you meant to have empty element tags there.

> </paymentTypes>
> </report>
> 
> In the context of <report> I want to pass all the 'paymentTypes/paymentType'
> nodes to a template, where @paymentTypeRef matches any @id attributes in
> <payments>...phew!  In the template I'll be outputting the @paymentTypeRef
> (amongst other things), but!!...I only want to output @paymentTypeRef if the
> sibling node before it hasn't got the same value.

Do you really want to process ALL paymentType elements that match any @id,
or do you just want to process the ones that match any @id and that meet
your other criteria?

I suspect the answer is the latter, in which case this is a classic
grouping scenario covered in the FAQ.

<!-- warning: untested, written-late-at-night,
possibly-retracted-in-the-morning code follows -->

<!-- a template that will handle a paymentType element -->
<xsl:template match="paymentType">
  <xsl:value-of select="@paymentTypeRef"/>
</xsl:template>

...

  <!-- instruction to the xsl processor to go apply the best matching
  templates for each of the nodes identified (this goes in some other
  template, of course) -->
  <xsl:apply-templates
  select="/report/paymentTypes/paymentType[
  @paymentTypeRef = /report/payments/@id and 
  @paymentTypeRef != ../following-sibling::paymentType/@paymentTypeRef]"/>

...The reason this should work is because equality comparisons of
node-sets like this return true if each set has a node with the same
string-value.

Now if you really do want to process all paymentType elements and you
were just giving the second condition as a restriction on what gets
output for some of them, just move the second half of the predicate into
the first template:

<xsl:template match="paymentType">
  <!-- stuff for just some paymentType elements ... -->
  <xsl:if test="@paymentTypeRef != ../following-sibling::paymentType/@paymentTypeRef]">
    <xsl:value-of select="@paymentTypeRef"/>
  </xsl:if>
  <!-- ... other stuff for all paymentType elements ... -->
</xsl:template>

...

  <xsl:apply-templates select="/report/paymentTypes/paymentType[
  @paymentTypeRef = /report/payments/@id]"/>

Alternatively you could put the predicate into the match attribute and
have separate templates for different classes of paymentType elements.


   - Mike
___________________________________________________________
Mike J. Brown, software engineer, Webb Interactive Services
XML/XSL stuff: http://www.skew.org/    http://www.webb.net/


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


Current Thread