xsl-list
[Top] [All Lists]

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

2004-08-12 11:02:18
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[(_at_)type = 'family'],
                             mods:namePart[(_at_)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[(_at_)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[(_at_)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[(_at_)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>