[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: RE: grouping content

Subject: Re: RE: grouping content
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Fri, 6 Apr 2001 20:38:07 +0100
xsl generate id with predicate
Hi Gavin,

> Now when i do that, for some reason if i try:
>
> <xsl:template match="World/NorthAmerica/US">
> I cannot just have:
>   <xsl:for-each select="[@Area and
> generate-id(.)=generate-id(key('LocationGroups',@Area))]">
>
> That returns an error

Square brackets in an expression indicate a *predicate*.  A predicate
is a test on a node set - it's used to filter in a subset of the node
set, the ones for which the test returns true.

The expression in the above isn't a legal XPath expression - you
haven't said what node set the predicate should be filtering.  That's
why it returns an error.

> So I tried removing the []'s, that still returns an error. 

XSLT processors always expect you to specify a *node set* in a select
attribute.  If you remove the []s in the above, you're left with a
*boolean* expression.  The XSLT processor can't iterate over true() or
false(), so it returns the error.

I think that you intended to do:

  <xsl:for-each select="Location[@Area and
       generate-id(.)=generate-id(key('LocationGroups',@Area))]">
     ...
  </xsl:for-each>

In other words, iterate over the Location elements that:

  (a) have an 'Area' attribute and
  (b) that are the first returned by the 'LocationGroups' key with
      that Area

In your second problem, assuming you don't know all the Areas and
Types in advance, you need multi-level keys to allow you to
quickly get the Location elements for a particular Area or of a
particular Type in a particular Area:

<xsl:key name="locs-by-area"
         match="Location" use="@Area" />
<xsl:key name="locs-by-area-and-type"
         match="Location" use="concat(@Area, ':', @Type)" />

In the template matching the US, then you can firstly select the
Location elements with unique Areas, and then select those with unique
Areas and Types, and finally select the relevant Rural or Urban
Location:

<xsl:template match="US">
   <!-- iterate over the Location elements with unique Areas -->
   <xsl:for-each select="Location[generate-id() =
                                  generate-id(key('locs-by-area', @Area))]">
      <!-- output a line giving the Area -->
      <xsl:value-of select="@Area" /><br /><br />
      <!-- iterate over the Location elements with this Area, but only
           those with unique Types -->
      <xsl:for-each
            select="key('locations-by-area', @Area)[generate-id() =
                       generate-id(key('locs-by-area-and-type',
                                       concat(@Area, ':', @Type))]">
         <!-- output a line giving the Type -->
         <xsl:value-of select="@Type" /><br />
         <!-- create a variable to hold the Locations with that Type
              in that Area -->
         <xsl:variable name="locations"
                       select="key('locs-by-area-and-type',
                                   concat(@Area, ':', @Type)" />
         <xsl:text>Rural: </xsl:text>
         <!-- give the value of the Location with Rural Scope -->
         <xsl:value-of select="$locations[@Scope = 'Rural']/@value" />
         <br />
         <xsl:text>Urban: </xsl:text>
         <!-- give the value of the Location with Urban Scope -->
         <xsl:value-of select="$locations[@Scope = 'Urban']/@value" />
         <br />
      </xsl:for-each>
   </xsl:for-each>
</xsl:template>

You can do this through applying templates instead, if you prefer that
style:

<xsl:template match="US">
   <!-- iterate over the Location elements with unique Areas -->
   <xsl:apply-templates mode="area-group"
      select="Location[generate-id() =
                       generate-id(key('locs-by-area', @Area))]" />
</xsl:template>

<xsl:template match="Location" mode="area-group">
   <!-- output a line giving the Area -->
   <xsl:value-of select="@Area" /><br /><br />
   <!-- iterate over the Location elements with this Area, but only
        those with unique Types -->
   <xsl:apply-templates mode="area-and-type-group"
      select="key('locations-by-area', @Area)[generate-id() =
                 generate-id(key('locs-by-area-and-type',
                                 concat(@Area, ':', @Type))]">
</xsl:template>

<xsl:template match="Location" mode="area-and-type-group">
   <!-- output a line giving the Type -->
   <xsl:value-of select="@Type" /><br />
   <!-- create a variable to hold the Locations with that Type
        in that Area -->
   <xsl:variable name="locations"
                 select="key('locs-by-area-and-type',
                             concat(@Area, ':', @Type)" />
   <!-- apply templates to the location with Rural scope -->
   <xsl:apply-templates select="$locations[@Scope = 'Rural']" />
   <!-- apply templates to the location with Urban scope -->
   <xsl:apply-templates select="$locations[@Scope = 'Urban']" />
</xsl:template>

<xsl:template match="Location">
   <xsl:value-of select="@Scope" />: <xsl:value-of select="@value" />
   <br />
</xsl:template>

I hope that helps,

Jeni

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



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


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.