[xsl] grouping + global variable (?) (was re: regexs, grouping (?) and XSLT2?)

Subject: [xsl] grouping + global variable (?) (was re: regexs, grouping (?) and XSLT2?)
From: Bruce D'Arcus <bdarcus@xxxxxxxxxxxxx>
Date: Thu, 12 Aug 2004 14:02:18 -0400
OK Jeni, moving to a new thread :-)

I just realized two problems with the grouping solution you came up
with (probably because my example highlighted one issue of the problem,
but not another!).  The serious one is that the suffixes are calculated
separately between a citation and a bibliography.

The issue can be dramatized with the below modified example document,
where each biblioref element is wrapped in its own citation.  The
result would be neither of them would have a suffix, while their bib
entries would.

So, basically, I need a way to specify to somehow use the same suffix
calculation in the citation and the bib entry.  Ideally, I want to just
be able to do a <xsl:value-of select="$suffix"/> whether I am
formatting the citation or the bibliography.

I don't understand how to do this, and a couple of hours of
experimenting doesn't appear to have gotten me closer to a solution.
(Further) help would be much appreciated!

Current stylesheet below the example.

Thanks,
Bruce

===== start example =====
<?xml version="1.0" encoding="utf-8"?>
<article xmlns="http://docbook.org/docbook-ng";>
  <info>
    <title>Test</title>
  </info>
  <section>
    <info>
      <title>Introduction</title>
    </info>
    <para>Some citations:
	<citation><biblioref linkend="one"/></citation>
	<citation><biblioref linkend="two"/></citation>
    </para>
  </section>
  <bibliography>
    <modsCollection xmlns="http://www.loc.gov/mods/v3";>
      <mods ID="one">
	<name type="personal">
	  <namePart type="given">John</namePart>
	  <namePart type="family">Doe</namePart>
	  <role>
	    <roleTerm type="text">author</roleTerm>
	  </role>
	</name>
	<titleInfo>
	  <title>Some Title</title>
	</titleInfo>
	<originInfo>
	  <dateIssued>1999</dateIssued>
	</originInfo>
      </mods>
      <mods ID="two">
	<name type="personal">
	  <namePart type="given">John</namePart>
	  <namePart type="family">Doe</namePart>
	  <role>
	    <roleTerm type="text">author</roleTerm>
	  </role>
	</name>
	<titleInfo>
	  <title>Another Title</title>
	</titleInfo>
	<originInfo>
	  <dateIssued>1999</dateIssued>
	</originInfo>
      </mods>
    </modsCollection>
  </bibliography>
</article>
===== end example =====

===== start xsl =====
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                xmlns:xs="http://www.w3.org/2001/XMLSchema";
                xmlns:xdt="http://www.w3.org/2003/11/xpath-datatypes";
		xmlns:str="http://example.org/xslt/functions";
		xmlns:db="http://docbook.org/docbook-ng";
		xmlns:mods="http://www.loc.gov/mods/v3";
		xmlns:cs="http://www.silmaril.ie/bibliox/v1";
		xmlns:bib="http://www.example.org/bib";
		xmlns="http://www.w3.org/1999/xhtml";
		exclude-result-prefixes="xs xdt mods str db"
                version="2.0">

<xsl:output method="xhtml" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="bibref" match="mods:mods" use="@ID" />

<!-- begin configuration options -->

<!-- first we specify a parameter for the external style file;
worry about later:

<xsl:param name="style-file-name" as="xs:string">
  <xsl:text>test</xsl:text>
</xsl:param>

<xsl:variable name="styles" as="document-node()"
  select="doc(concat($style-file-name, '.csl'))" />
-->

<!-- biborder template simply determines the order of processing -->

<xsl:template name="biborder">
  <xsl:apply-templates select="mods:titleInfo"/>
  <xsl:apply-templates select="mods:originInfo"/>
  <xsl:apply-templates select="mods:relatedItem"/>
  <xsl:apply-templates select="mods:location"/>
</xsl:template>

<!-- punctuation variables -->

<xsl:variable name="title-before">
  <xsl:text></xsl:text>
</xsl:variable>

<xsl:variable name="title-after">
  <xsl:text> </xsl:text>
</xsl:variable>

<xsl:variable name="creator-before">
  <xsl:text></xsl:text>
</xsl:variable>

<xsl:variable name="creator-after">
  <xsl:text> </xsl:text>
</xsl:variable>

<xsl:variable name="year-before">
  <xsl:text>(</xsl:text>
</xsl:variable>

<xsl:variable name="year-after">
  <xsl:text>) </xsl:text>
</xsl:variable>

<xsl:variable name="origin-before">
  <xsl:text>(</xsl:text>
</xsl:variable>

<xsl:variable name="origin-after">
  <xsl:text>)</xsl:text>
</xsl:variable>

<xsl:variable name="volume-before">
  <xsl:text>v.</xsl:text>
</xsl:variable>

<xsl:variable name="volume-after">
  <xsl:text></xsl:text>
</xsl:variable>

<xsl:variable name="issue-before">
  <xsl:text>, </xsl:text>
</xsl:variable>

<xsl:variable name="issue-after">
  <xsl:text></xsl:text>
</xsl:variable>

<xsl:variable name="location-before">
  <xsl:text>available from: </xsl:text>
</xsl:variable>

<xsl:variable name="location-after">
  <xsl:text>, </xsl:text>
</xsl:variable>

<xsl:variable name="genre-before">
  <xsl:text>, </xsl:text>
</xsl:variable>

<xsl:variable name="genre-after">
  <xsl:text></xsl:text>
</xsl:variable>

<xsl:variable name="place-before">
  <xsl:text></xsl:text>
</xsl:variable>

<xsl:variable name="place-after">
  <xsl:text>:</xsl:text>
</xsl:variable>

<xsl:variable name="publisher-before">
  <xsl:text></xsl:text>
</xsl:variable>

<xsl:variable name="publisher-after">
  <xsl:text></xsl:text>
</xsl:variable>

<!-- end configuration options -->

<xsl:template match="db:article">
  <html>
    <head>
      <xsl:apply-templates select="db:info"/>
      <style type="text/css">
	body { font-family: georgia, sans; font-size: 11px; line-height: 15px;}
	#content { width: 500px; position: center; margin: auto; margin-top:
40px; }
	a { text-decoration: none; color: black; }
	a:hover { background: #F3FCC0; }
      </style>
    </head>
    <body>
      <div id="content">
	<xsl:apply-templates select="db:section | db:chapter"/>
	<xsl:apply-templates select="db:bibliography"/>
      </div>
    </body>
  </html>
</xsl:template>

<xsl:template match="db:info">
  <title>
    <xsl:value-of select="db:title"/>
  </title>
</xsl:template>

<xsl:template match="db:section">
  <div class="section">
    <xsl:apply-templates/>
  </div>
</xsl:template>

<xsl:template match="db:section/db:info">
  <h4>
    <xsl:value-of select="db:title"/>
  </h4>
</xsl:template>


<xsl:template match="db:para"> <p> <xsl:apply-templates/> </p> </xsl:template>

<xsl:template match="db:bibliography">
  <div id="bibliography">
    <h4>References</h4>
    <xsl:apply-templates/>
  </div>
</xsl:template>

<xsl:function name="bib:grouping-key" as="xs:string">
  <xsl:param name="mods" as="element(mods:mods)" />
  <xsl:value-of separator=";">
    <xsl:for-each select="$mods/mods:name">
      <xsl:value-of
        select="string-join((mods:namePart[@type = 'family'],
                             mods:namePart[@type = 'given']), ',')" />
    </xsl:for-each>
  </xsl:value-of>
</xsl:function>

<!-- this function doesn't work, but leave here for now -->
<xsl:function name="bib:author-year.suffix">

  <xsl:variable name="idref" select="@linkend"/>
  <!-- ## Grab the MODS record from the reference list -->
  <xsl:variable name="bibref" select="//mods:mods[@ID=$idref]" />
  <xsl:for-each-group select="$bibref" group-by="bib:grouping-key(.)">
    <xsl:sort select="current-grouping-key()"/>
    <xsl:for-each-group select="current-group()"
			group-by="xs:integer(substring(mods:originInfo/mods:dateIssued|
			mods:relatedItem/mods:part/mods:date,1,4))">
      <xsl:sort select="current-grouping-key()" />
      <xsl:variable name="year" as="xs:integer"
		    select="current-grouping-key()"/>
      <xsl:variable name="first" as="xs:boolean" select="position() =
1" />
      <xsl:for-each select="current-group()">
	<xsl:if test="last() > 1">
	  <xsl:number value="position()" format="a"/> <!-- added select -->
	</xsl:if>
      </xsl:for-each>
    </xsl:for-each-group>
  </xsl:for-each-group>
</xsl:function>

<xsl:template match="db:citation">
  <xsl:text>(</xsl:text>
  <xsl:apply-templates/>
  <xsl:text>)</xsl:text>
</xsl:template>

<xsl:template match="db:biblioref">
  <xsl:call-template name="cite-content"/>
  <xsl:if test="position() != last()">; </xsl:if>
 </xsl:template>

<!-- Not important now, but ultimately the below needs to be
parameterized, so that
the below corresponds to the author-year style, but other code would
handle, say,
numeric citations, which could be (1-3). -->

<xsl:template name="cite-content">
  <xsl:variable name="idref" select="@linkend"/>
  <!-- ## Grab the MODS record from the reference list -->
  <xsl:variable name="bibref" select="//mods:mods[@ID=$idref]" />
<!--  <xsl:variable name="bibref" select="key('bibref',
db:biblioref/@linkend)" /> -->
  <xsl:for-each-group select="$bibref" group-by="bib:grouping-key(.)">
    <xsl:sort select="current-grouping-key()"/>

<xsl:for-each-group select="current-group()"

group-by="xs:integer(substring(mods:originInfo/mods:dateIssued|
			mods:relatedItem/mods:part/mods:date,1,4))">
      <xsl:sort select="current-grouping-key()" />
      <xsl:for-each select="current-group()">
	<a>
	  <xsl:attribute name="href">
	    <xsl:value-of select="concat('#',@ID)"/>
	  </xsl:attribute>
	  <xsl:apply-templates select="." mode="names" />
	  <xsl:text>, </xsl:text>
	  <xsl:value-of
select="xs:integer(substring(mods:originInfo/mods:dateIssued|
			mods:relatedItem/mods:part/mods:date,1,4))" />
	  <xsl:if test="last() > 1">
	    <xsl:number value="position()" format="a"/>
	    <xsl:if test="position() != last()">, </xsl:if>
	  </xsl:if>
	</a>
      </xsl:for-each>
    </xsl:for-each-group>
  </xsl:for-each-group>
</xsl:template>

<xsl:template match="mods:modsCollection">
  <xsl:variable name="bibref" select="mods:mods" />
  <xsl:for-each-group select="$bibref" group-by="bib:grouping-key(.)">
    <xsl:sort select="current-grouping-key()"/>
    <xsl:for-each-group select="current-group()"
			group-by="xs:integer(substring(mods:originInfo/mods:dateIssued|
			mods:relatedItem/mods:part/mods:date,1,4))">
      <xsl:sort select="current-grouping-key()" />
      <xsl:variable name="year" as="xs:integer"
		    select="current-grouping-key()"/>
      <xsl:variable name="first" as="xs:boolean" select="position() =
1" />
      <xsl:for-each select="current-group()">
	<p>
	  <xsl:attribute name="id">
	    <xsl:value-of select="@ID"/>
	  </xsl:attribute>
	  <span class="creator">
	    <xsl:value-of select="$creator-before"/>
	    <xsl:choose>
	      <xsl:when test="$first and position()=1">
		<xsl:apply-templates select="." mode="names"/>
		<xsl:text> </xsl:text>
	      </xsl:when>
	      <xsl:otherwise>.</xsl:otherwise>
	    </xsl:choose>
	    <xsl:value-of select="$creator-after"/>
	  </span>
	  <span class="year">
	    <xsl:value-of select="$year-before"/>
	    <xsl:value-of select="$year" />
	    <xsl:if test="last() > 1">
	      <xsl:number value="position()" format="a"/> <!-- added select -->
	    </xsl:if>
	    <xsl:value-of select="$year-after"/>
	  </span>
	  <xsl:call-template name="biborder"/>
	  <xsl:text>.</xsl:text>
	</p>
      </xsl:for-each>
    </xsl:for-each-group>
  </xsl:for-each-group>
</xsl:template>

<xsl:template match="mods:titleInfo">
  <span class="title">
    <xsl:value-of select="$title-before"/>
    <xsl:apply-templates select="mods:title"/>
    <xsl:apply-templates select="mods:subTitle"/>
    <xsl:value-of select="$title-after"/>
  </span>
</xsl:template>

<xsl:template match="mods:title">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="mods:subTitle">
  <xsl:text>: </xsl:text>
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="mods:mods" mode="names">
  <xsl:for-each select="mods:name">
    <xsl:value-of select="mods:namePart[@type = 'family']" />
    <xsl:choose>
      <xsl:when test="position() = last()" />
      <xsl:when test="position() = last() - 1"> and </xsl:when>
      <xsl:otherwise>, </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each>
</xsl:template>

<xsl:template match="mods:originInfo">
  <xsl:if test="mods:place">
    <xsl:value-of select="$origin-before"/>
    <xsl:apply-templates select="mods:place"/>
    <xsl:apply-templates select="mods:publisher"/>
    <xsl:value-of select="$origin-after"/>
  </xsl:if>
</xsl:template>

<xsl:template match="mods:place">
  <xsl:value-of select="$place-before"/>
  <xsl:apply-templates/>
  <xsl:value-of select="$place-after"/>
</xsl:template>

<xsl:template match="mods:publisher">
   <xsl:value-of select="$publisher-before"/>
  <xsl:apply-templates/>
   <xsl:value-of select="$publisher-after"/>
</xsl:template>

</xsl:stylesheet>

Current Thread