[xsl] modes and temp trees (was Re: [xsl] grouping + global variable (?))

Subject: [xsl] modes and temp trees (was Re: [xsl] grouping + global variable (?))
From: Bruce D'Arcus <bdarcus@xxxxxxxxxxxxx>
Date: Sat, 14 Aug 2004 16:49:55 -0400
I'm sorry to take up so much bandwidth on this (and thanks in advance
for the continued patience; I promise not to make a habit of it), but
I'm still stuck on figuring this out.

I took Wendell's suggestion and reworked the modes, and changed the
previous "phase-2" mode and made it default.  The bibliography
generation now works beautifully and I've gotten things much better
modularized.  But I can't get the citation mode to work.  Much of the
time, I'm sending Saxon into an infinite loop trying to figure it out!

Again taking my simple example doc (at bottom), how do I modify the
below stylesheet to correctly use the temporary tree for both the
bibliography AND the citation modes?  I need to get it to where this
simple template (near the bottom) works:

<xsl:template match="mods:mods" mode="citation">
  <xsl:apply-templates select="mods:name" mode="citation"/>
  <xsl:value-of select="mods:year"/>
  <xsl:apply-templates select="mods:key"/>
</xsl:template>

The mods:key and mods:year elements are the ones created in the
intermediate step, and the same expressions work fine in the
bibliography mode.  Currently I end up with output like this, where the
year and suffix get dropped:

	(<a href="#one">Doe</a>; <a href="#two">Doe</a>; <a href="#three">Doe,
Jones and Smith</a>)

I'm also still unclear on how I should be properly controlling
namespaces across these different modes.

Bruce

=== 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="http://www.loc.gov/mods/v3";
		xmlns:cs="http://www.silmaril.ie/bibliox/v1";
		xmlns:bib="http://www.example.org/bib";
		xmlns:xhtml="http://www.w3.org/1999/xhtml";
		exclude-result-prefixes="xs xdt str db mods xhtml cs bib"
                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 -->

<!-- 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>

<xsl:variable name="reftype">
  <xsl:choose>
    <xsl:when test="not[mods:relatedItem[@type='host']]">
      <xsl:text>book</xsl:text>
    </xsl:when>
    <xsl:when

test="mods:relatedItem[@type='host']/mods:originInfo/mods:
issuance='continuing'">
      <xsl:text>article</xsl:text>
    </xsl:when>
    <xsl:when

test="mods:relatedItem[@type='host']/mods:originInfo/mods:
issuance='monographic'">
      <xsl:text>chapter</xsl:text>
    </xsl:when>
  </xsl:choose>
</xsl:variable>

<!-- long list of punctuation variables -->

<xsl:variable name="title-before">
  <xsl:choose>
    <xsl:when test="$reftype='chapter'">
      <xsl:text></xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text></xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<xsl:variable name="title-after">
  <xsl:choose>
    <xsl:when test="$reftype='chapter'">
      <xsl:text></xsl:text>
    </xsl:when>
    <xsl:otherwise>
      <xsl:text></xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</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="/">
  <html xmlns="http://www.w3.org/1999/xhtml";>
    <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/>
      </div>
    </body>
  </html>
</xsl:template>

<xsl:template match="db:info">
  <xsl:apply-templates select="db: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">
    <h3>References</h3>
    <xsl:apply-templates/>
  </div>
</xsl:template>

<!-- MODS stuff -->

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

<!-- first create a temporary tree -->
<!-- NOTE: If I remove the bib mode on the apply-templates below,
Saxon appears to go into an infinite loop -->
<xsl:template match="mods:modsCollection">
  <xsl:variable name="temp">
    <xsl:apply-templates select="." mode="processed-bibrefs"/>
  </xsl:variable>
  <xsl:apply-templates select="$temp" mode="bibliography"/>
</xsl:template>

<!-- next, group, sort, and generate year and suffix elements from
raw biblist to create a processed biblist -->
<xsl:template match="mods:modsCollection" mode="processed-bibrefs">
  <xsl:copy>
    <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()">
	  <mods ID="{@ID}">
	    <year>
	      <xsl:value-of select="current-grouping-key()"/>
	    </year>
	    <xsl:if test="last() > 1">
	      <key type="year-suffix">
		<xsl:number value="position()" format="a"/>
	      </key>
	    </xsl:if>
	    <xsl:copy-of select="*"/>
	  </mods>
	</xsl:for-each>
      </xsl:for-each-group>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

<!-- take processed biblist and run templates on them in bib mode -->
<xsl:template match="mods:modsCollection" mode="bibliography">
  <xsl:apply-templates select="mods:mods" mode="bibliography"/>
</xsl:template>

<xsl:template match="mods:mods" mode="bibliography">
  <p class="bibref" id="{@ID}">
    <span class="creator">
      <xsl:apply-templates select="mods:name" mode="bibliography"/>
    </span>
    <xsl:apply-templates select="mods:year"/>
    <xsl:apply-templates select="mods:titleInfo" mode="bibliography"/>
    <xsl:apply-templates select="mods:originInfo" mode="bibliography"/>
    <xsl:apply-templates select="mods:relatedItem" mode="bibliography"/>
    <xsl:apply-templates select="mods:location" mode="bibliography"/>
  </p>
</xsl:template>

<xsl:template match="mods:name" mode="bibliography">
  <xsl:apply-templates select="mods:namePart"/>
  <xsl:choose>
    <xsl:when test="position() = last()" />
    <xsl:when test="position() = last() - 1"> and </xsl:when>
    <xsl:otherwise>, </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="mods:namePart[@type='given']">
  <xsl:apply-templates/>
  <xsl:text> </xsl:text>
</xsl:template>

<xsl:template match="mods:namePart[@type='family']">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="mods:year">
  <span class="year">
    <xsl:value-of select="$year-before"/>
    <xsl:apply-templates/>
<!-- we can access newly creatod key element to append suffix -->
    <xsl:apply-templates select="../mods:key"/>
    <xsl:value-of select="$year-after"/>
  </span>
</xsl:template>

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

<xsl:template match="mods:titleInfo" mode="bibliography">
  <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:originInfo" mode="bibliography">
  <xsl:if test="mods:place">
    <span class="origin">
      <xsl:value-of select="$origin-before"/>
      <xsl:apply-templates select="mods:place"/>
      <xsl:apply-templates select="mods:publisher"/>
      <xsl:value-of select="$origin-after"/>
    </span>
  </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>

<!-- begin citation processing; something's wrong with the modes -->

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

<xsl:template match="db:biblioref">
  <xsl:variable name="idref" select="@linkend"/>
  <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:for-each select="current-group()">
	<a>
	  <xsl:attribute name="href">
	    <xsl:value-of select="concat('#',@ID)"/>
	  </xsl:attribute>
	  <xsl:apply-templates select="." mode="citation" />
	  <xsl:if test="position() != last()">, </xsl:if>
	</a>
      </xsl:for-each>
    </xsl:for-each-group>
  </xsl:for-each-group>
  <xsl:if test="position() != last()">; </xsl:if>
</xsl:template>

<xsl:template match="mods:name" mode="citation">
  <xsl:apply-templates 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:template>

<xsl:template match="mods:mods" mode="citation">
  <xsl:apply-templates select="mods:name" mode="citation"/>
  <xsl:value-of select="mods:year"/>
  <xsl:apply-templates select="mods:key"/>
</xsl:template>

</xsl:stylesheet>

=== input ===

<?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"/><biblioref
    linkend="two"/><biblioref linkend="three"/></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>
      <mods ID="three">
	<name type="personal">
	  <namePart type="given">John</namePart>
	  <namePart type="family">Doe</namePart>
	  <role>
	    <roleTerm type="text">author</roleTerm>
	  </role>
	</name>
	<name type="personal">
	  <namePart type="given">Jane</namePart>
	  <namePart type="family">Jones</namePart>
	  <role>
	    <roleTerm type="text">author</roleTerm>
	  </role>
	</name>
	<titleInfo>
	  <title>Some Title</title>
	</titleInfo>
	<originInfo>
	  <dateIssued>1999</dateIssued>
	</originInfo>
      </mods>
    </modsCollection>
  </bibliography>
</article>

Current Thread