Re[2]: numbering - counting - grouping

Subject: Re[2]: numbering - counting - grouping
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Fri, 10 Nov 2000 11:18:24 +0000
Barbara,

> I manage to output 'type is <something>' once for each group of
> contributors, which are of the same type. But I must find a way to add to
> this an enumeration as shown above, and I don't know how to do it.

Given that you know the types that might be involved (AU, ED & CON),
and you know that the AUs (if any) will be first, then the EDs (if
any) and then the CONs (if any), then you can work out the numbering
that you need to give each of them statically.  First, set up
variables holding the contributors in each of the groups:

  <xsl:variable name="authors" select="contributor[type='AU']" />
  <xsl:variable name="editors" select="contributor[type='ED']" />
  <xsl:variable name="others" select="contributor[type='CON']" />

Now, authors are always going to be first, and therefore always
numbered 1 if there are any:

  <xsl:if test="$authors">
     <xsl:text />1. type is AU<br />
     <xsl:apply-templates select="$authors" />
  </xsl:if>

Editors are next: they are numbered 1 if there are no authors, and 2
if there are:

  <xsl:if test="$editors">
    <xsl:choose>
       <xsl:when test="$authors">1.</xsl:when>
       <xsl:otherwise>2.</xsl:otherwise>
    </xsl:choose>
    <xsl:text /> type is ED<br />
    <xsl:apply-templates select="$editors" />
  </xsl:if>

Other contributors are next: they are numbered 1 if there are no
authors or editors, 2 if there are either authors or editors but not
both and 3 if there are both authors and editors.

  <xsl:if test="$contributors">
     <xsl:choose>
        <xsl:when test="$authors and $editors">3.</xsl:when>
        <xsl:when test="$authors or $editors">2.</xsl:when>
        <xsl:otherwise>1.</xsl:otherwise>
     </xsl:choose>
     <xsl:text /> type is CON<br />
     <xsl:apply-templates select="$contributors" />
  </xsl:if>

With a template that adds the names of the contributors:

<xsl:template match="contributor">
   <xsl:value-of select="name" /><br />
</xsl:template>

you have a solution.  This solution only works if you know the types
of the contributors in advance, and it gives you complete control over
the order in which you want to show them.  There is another solution
that will work if you don't know all the types (or allow you to expand
them later on), is shorter, but gives you somewhat less control over
the ordering of the types in the output.

You can apply templates to only the first uniquely-typed contributors
within the list:

   <xsl:apply-templates
     select="contributor[not(type = preceding-sibling::contributor/type)]">

This applies templates to only those contributors who don't have any
preceding siblings that have the same type as they do.  In the node
set to which the templates are applied, there will be one AU, one
ED, and one CON (if there are such).  Their position within that list
is the number that you're after.

You can get the rest of the contributors with the same position with
the expression:

  following-sibling::contributor[type = current()/type]

Thus, the contributor-matching template (which will only be applied
once for each type of contributor) looks something like:

<xsl:template match="contributor">
   <xsl:value-of select="position()" />. type is <xsl:text />
   <xsl:value-of select="type" /><br />
   <xsl:for-each
         select=". | following-sibling::contributor[type = current()/type]">
      <xsl:value-of select="name" /><br />
   </xsl:for-each>
</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