<?xml version="1.0"?>
<!--
     $Id: trdoc-data.xsl,v 2.97 2015/08/31 05:54:23 denis Exp $
     -->
<?xml-stylesheet href="http://www.w3.org/StyleSheets/base.css" type="text/css"?>
<?xml-stylesheet href="http://www.w3.org/2002/02/style-xsl.css" type="text/css"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:trd="http://www.w3.org/2001/10/trdoc-data.xsl"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:org="http://www.w3.org/2001/04/roadmap/org#"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:contact="http://www.w3.org/2000/10/swap/pim/contact#"
exclude-result-prefixes="html trd org xs rdf contact">

  <xsl:output method="xml" encoding='utf-8' use-character-maps="nbsp"/>

  <xsl:character-map name="nbsp">
    <xsl:output-character character="&#160;" string=" "/>
  </xsl:character-map>

  <div xmlns="http://www.w3.org/1999/xhtml">
    <h1>
    <a href="http://www.w3.org/">
      <img src="http://www.w3.org/Icons/w3c_home" alt="W3C" />
    </a>XSLT Templates to extract metadata from a 
    <a href="../../Guide/pubrules">pubrules</a>compliant 
    <a href="../../TR/">TR document</a></h1>
    <h2>Status</h2>
    <p>The templates in this stylesheet are used in several other
    ones. Please don't modify it without letting me know and don't
    break the current exposed API in any case.</p>
    <p>If you need to do any modifications, please use the 
    <a href="../11/trdoc-data-ts">little test suite</a>to test it
    doesn't break the exposed API.</p>
    <p>Note that the dependances between the templates must not be
    broken nor changed as the pubrules checker relies on this
    dependancy order.</p>
    <p>Please don't try to make it more flexible: it's used as the
    base of the 
    <a href="../07/pubrules-form">pubrules checker</a>and must only
    extract data from 
    <a href="../../Guide/pubrules">pubrules</a>compliant
    document.</p>
    <h2>Variables</h2>

    <dl>
    <dt>trd:divHead</dt>
    <dd>Fragment of the result tree with the nodeset containing the &lt;div class="head"&gt; section</dd>
  </dl>

    <h2>Templates</h2>

    <dl>

      <dt>trd:getStatusSubtitle</dt>
      <dd>Returns the complete subtitle matching "W3C <var>Status</var> <var>DD</var> <var>Month</var> <var>YYYY</var>"</dd>

      <dt>trd:getStatus</dt>
      <dd>Returns the status of the document (one amonst Recommendation, Proposed Recommendation, Candidate Recommendation, Working Draft, Note, Rescinded Recommendation, Proposed Edited Recommendation, Member Submission, Team Submission, Interest Group Report)</dd>
      <dd>Depends on <code>trd:getStatusSubtitle</code> and its right formatting</dd>

      <dt>trd:getShortStatus</dt>
      <dd>Returns the abbreviation for the status of the document (one amongst REC, PR, CR, WD, NOTE, PER, RSCND, SUBM, XGR)</dd>
      <dd>Depends on <code>trd:getStatus</code></dd>

      <dt>trd:getOrigin</dt>
      <dd>For Submissions and Notes, returns the type of the originator of the document (for submissions, either Team or Member; for Notes, WG, IG or CG)</dd>
      <dd>Depends on <code>trd:getShortStatus</code> (and <code>trd:getStatus</code>)</dd>

      <dt>trd:is5February2004</dt>
      <dd>Returns 'yes' if the document include the expression "5 February 2004" in the status section), nothing otherwise</dd>

      <dt>trd:isCallForExclusion</dt>
      <dd>Returns 'yes' if the document include the expression "call for exclusion" in the status section), nothing otherwise</dd>

      <dt>trd:isFirstPublicWorkingDraft</dt>
      <dd>Returns 'yes' if the document is a First Public Working Draft (ie: the expression "First Public Working Draft" is present in the status section), nothing otherwise</dd>
      <dd>Depends on <code>trd:getShortStatus</code></dd>

      <dt>trd:isLastCall</dt>
      <dd>Returns 'yes' if the document is in last call, nothing otherwise</dd>
      <dd>Depends on <code>trd:getShortStatus</code></dd>

      <dt>trd:underW3CPatentPolicy</dt>
      <dd>Returns 'yes' if the document was produced under the W3C Patent Policy</dd>
      <dd>Looks for the expressions "W3C Patent Policy" and "5 Feburary 2003", and checks that the doc is not "not targeting Rec"</dd>

      <dt>trd:underCPP</dt>
      <dd>Returns 'yes' if the document was produced under the CPP amended by the W3C PP procedure</dd>
      <dd>Looks for link to W3C PP procedure in SOTD</dd>

      <dt>trd:isW3CPatentPolicy</dt>
      <dd>Returns 'yes' if the document include the expression "W3C Patent Policy" in the status section), nothing otherwise</dd>

      <dt>trd:Informative</dt>
      <dd>Return 'yes', if the document include the expression "This document is informative only" (per pubrules), nothing otherwise</dd>

      <dt>trd:getDate</dt>
      <dd>Returns the English date of the document (formatted as <var>DD</var> <var>Month</var> <var>YYYY</var>)</dd>
      <dd>Depends on <code>trd:getStatusSubtitle</code> and its right formatting</dd>

      <dt>trd:getNumericDate</dt>
      <dd>Returns the numeric date of the document (formatted as <var>YYYY</var><var>MM</var><var>DD</var>)</dd>
      <dd>Depends on <code>trd:getDate</code></dd>

      <dt>trd:getTitle</dt>
      <dd>Returns the title of the document</dd>

      <dt>trd:getVersionURI</dt>
      <dd>Takes a <var>which</var> parameter amongst "this","latest","previous" (case sensitive) and returns the corresponding version URI</dd>

      <dt>trd:hasNewShortname</dt>
      <dd>Takes no argument, and returns 'yes' if the document's shortname has changed (i.e. differs in previous and latest version URIs)</dd>

      <dt>trd:getEditorsSectionName</dt>
      <dd>Returns the name of the editors section ("Editor" or "Author")</dd>

      <dt>trd:formatEditorName</dt>
      <dd>This template takes a <var>trd:EditorName</var> parameter and a <var>trd:EditorMailbox</var> parameter and returns the first paramater with a comma appended. This template is to be overriden to format the list of editors created by the <code>trd:getEditorsList</code> template</dd>
      
      <dt>trd:getEditorsList</dt>
      <dd>Returns the list of editors. </dd>
      <dd>Depends on <code>trd:getEditorsSectionName</code></dd>

      <dt>trd:getActivity</dt>
      <dd>This template looks into the SOTD and catches any link to an activity homepage or an activity statement, and returns the absolute URI of those. The default formatting is a comma separated list but can be changed by overriding the <code>trd:formatActivityHP</code> and <code>trd:formatActivityStatement</code> templates</dd>

      <dt>trd:formatActivityHP and trd:formatActivityStatement, trd:formatWorkingGroupHP</dt>
      <dd>These templates take a <var>uri</var> parameter and returns this parameter with a comma and a space appended. This template is to be overriden to format the list of activities related URIs created by the <code>trd:getActivity</code> template</dd>
      
      <dt>trd:getWorkingGroup</dt>
      <dd>This template looks into the SOTD and catches any link to a known public page about working groups, and returns the absolute URI of those</dd>
      <dd>Known public pages for Working Groups relies on <a href="/2000/04/mem-news/public-groups.rdf">the RDF list of W3C Working Groups with their home pages</a> and on <a href="/2001/07/pubrules-copyright.xml">an additional source for special cases</a> (e.g. Working Group without a public home page)</dd>

      <dt>trd:getFeedbackDueDate</dt>
      <dd>This template tries to extract all the dates from the SOTD separated by white spaces; only the dates posterior to the date of the doc and inferior to one year later are extracted... If there is only one, there is a good chance that it's the deadline for feedback</dd>

      <dt>trd:getErrata</dt>
      <dd>This template extracts the URI of the errata for a Recommendation</dd>

      <dt>trd:getTranslations</dt>
      <dd>This template extracts the URI of the translations page (provided that the link is formatted as per http://www.w3.org/Guide/pubrules#head 1.7.9, required for Recommendations)</dd>

      <dt>trd:getImplReport</dt>
      <dd>This template extracts the URI of the implementation/interoperability report (by looking in the SOTD for links whose test contains interoperability or implementation)</dd>

      <dt>trd:getProcessRevision</dt>
      <dd>This template extracts the URI of the process document governing the publication.</dd>
    </dl>

    <h2>Functions</h2>

    <p>Same as templates (with "yes" answers replaced by boolean values), 
    but in addition:</p>

    <dl>
      <dt>trd:getStatusSection</dt>
      <dd>Returns status section of the document</dd>
      <dt>trd:getAbstract</dt>
      <dd>Returns abstract of the document</dd>
      <dt>trd:isWD</dt>
      <dd>Returns true if any type of WD</dd>
      <dt>trd:isFirstPublicWorkingDraft</dt>
      <dd>Returns true if FPWD</dd>
      <dt>trd:isLastCall</dt>
      <dd>Returns true if LCWD</dd>
      <dt>trd:isPR</dt>
      <dd>Returns true if PR</dd>
      <dt>trd:isPER</dt>
      <dd>Returns true if PER</dd>
      <dt>trd:isCR</dt>
      <dd>Returns true if CR</dd>
      <dt>trd:isREC</dt>
      <dd>Returns true if REC</dd>
      <dt>trd:latestVersionURI</dt>
      <dt>trd:thisVersionURI</dt>
      <dt>trd:previousVersionURI</dt>
    </dl>

    <hr />
    <address>$Id: trdoc-data.xsl,v 1.126 2007/05/17 16:03:37
    ijacobs Exp $ 
    <br />
    Ian Jacobs
    </address>
    <hr />
  </div>

  <xsl:variable name="trd:divHead" select="//(html:div|html:section)[@class='head']"/>
  <xsl:variable name="trd:body" select="//html:body" />

  <xsl:variable name="pubrules-copyright"
  select="document('../07/pubrules-copyright.xml')" />

  <xsl:variable name="public-groups"
  select="document('../../2000/04/mem-news/public-groups.rdf')" />

  <xsl:variable name="statuses" 
                select="('Recommendation',
                         'Proposed Recommendation',
                         'Proposed Edited Recommendation',
                         'Candidate Recommendation',
                         'Working Draft',
                         'Last Call Working Draft',
                         'First Public Working Draft',
                         'First Public and Last Call Working Draft',
                         'Working Group Note',
                         'Working Group Note',
                         'Interest Group Note',
                         'Coordination Group Note',
                         'Member Submission',
                         'Team Submission',
                         'Incubator Group Report'
                         )"/>

  <xsl:variable name="statusabbrevs" 
                select="('REC',
                         'PR',
                         'PER',
                         'CR',
                         'WD',
                         'WD',
                         'WD',
                         'WD',
                         'NOTE',
                         'NOTE',
                         'NOTE',
                         'NOTE',
                         'SUBM',
                         'SUBM',
                         'XGR'
                         )"/>

  <xsl:variable name="trstatus"
                select="('rec-tr',
                         'pr-tr',
                         'per-tr',
                         'cr-tr',
                         'ord-wd-tr',
                         'lc-wd-tr',
                         'fpwd-wd-tr',
                         'fpwdlc-wd-tr',
                         'wg-note-tr',
                         'fpwg-note-tr',
                         'fpig-note-tr',
                         'cg-note-tr',
                         'mem-subm',
                         'team-subm',
                         'xgr'
                         )"/>

  <xsl:variable name="origins" 
                select="('',
                         '',
                         '',
                         '',
                         '',
                         'WG',
                         '',
                         '',
                         '',
                         '',
                         'IG',
                         'CG',
                         'Member',
                         'Team',
                         '' 
                         )"/>

  <!-- trd:getStatus -->

  <xsl:template name="trd:getStatus">
    <xsl:copy-of select="trd:getStatus()"/>
  </xsl:template>

  <xsl:function name="trd:getStatus" as="xs:string">
    <xsl:variable name="statusstr">
      <xsl:for-each select="distinct-values($statuses)">
	<xsl:variable name="s" select="."/>
	<xsl:if test="$trd:divHead//html:h2[contains(normalize-space(.),concat('W3C ',$s))]"><xsl:value-of select="$s"/></xsl:if>
      </xsl:for-each>
    </xsl:variable>
    <xsl:if test="$statusstr=''">
      <xsl:message>
	Error: No document status found.
      </xsl:message>
    </xsl:if>
    <xsl:value-of select="$statusstr"/>
  </xsl:function>
  
  <xsl:variable name="status" select="trd:getStatus()"/>

  <!-- trd:getStatusText -->
  <xsl:function name="trd:getStatusText">
    <xsl:param name="docstatus" as="xs:string"/>
    <xsl:value-of select="$statuses[index-of($trstatus,$docstatus)]"/>
  </xsl:function>

  <!-- trd:getShortStatus -->

  <xsl:template name="trd:getShortStatus">
    <xsl:value-of select="trd:getShortStatus()"/>
  </xsl:template>

  <xsl:function name="trd:getShortStatus">
    <xsl:choose>
      <xsl:when test="$status='Working Group Note'">
        <xsl:value-of select="$statusabbrevs[index-of(distinct-values($statuses),$status)]"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:if test="$status!=''">
          <xsl:value-of select="$statusabbrevs[index-of($statuses,$status)]"/>
        </xsl:if>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <!-- The following function intends to provide backup if the
       short status cannot be determined via trd:getShortStatus.
       Example: "Editor's Draft" -->

  <xsl:function name="trd:getShortStatusFromURI">
    <xsl:variable name="uri" select="trd:thisVersionURI()"/>
    <xsl:choose>
      <xsl:when test="$uri=''">
	<xsl:message>
	      Error! Empty this version URI.
	</xsl:message>
      </xsl:when>
      <xsl:otherwise>
	<xsl:analyze-string select="normalize-space($uri)" 
			    regex=".*/([A-Z]+)\-.+\-\d{{8}}/?$">
	  <xsl:matching-substring>
	    <xsl:variable name="st" select="regex-group(1)"/>
	    <xsl:choose>
	      <xsl:when test="$st=$statusabbrevs">
		<xsl:value-of select="$st"/>
	      </xsl:when>
	      <xsl:otherwise>
		<xsl:message>
		  Error! Did not find valid short status from this version URI: <xsl:value-of select="$st"/>
		</xsl:message>
	      </xsl:otherwise>
	    </xsl:choose>
	  </xsl:matching-substring>
	</xsl:analyze-string>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <!-- trd:getStatusSubtitle -->

  <xsl:template name="trd:getStatusSubtitle">
    <xsl:copy-of select="trd:getStatusSubtitle()"/>
  </xsl:template>

  <xsl:function name="trd:getStatusSubtitle">
    <xsl:if test="$status!=''">
      <xsl:copy-of select="$trd:divHead//html:h2[contains(normalize-space(.),$status)]"/>
    </xsl:if>
  </xsl:function>

  <xsl:variable name="statusH2" select="trd:getStatusSubtitle()"/>

  <!-- trd:getOrigin -->

  <xsl:template name="trd:getOrigin">
    <xsl:if test="$status!=''">
      <xsl:value-of select="$origins[index-of(distinct-values($statuses),$status)]"/>
    </xsl:if>
  </xsl:template>

  <!-- trd:getStatusSection -->

  <!-- The status section consists of all the sibling elements
       following the "status of this document" h2, up to but
       not including the next h2 element. Note that the next
       h2 may be part of a div (hence "descendant-or-self") and
       that the siblings of the first h2 may be text nodes
       (e.g., if the status h2 is part of a div with mixed content). -->

  <xsl:function name="trd:getStatusSection">
    <xsl:if test="$status!=''">
      <xsl:variable name="sotdH2" select="($trd:body//html:h2[matches(normalize-space(.),'status\s+of\s+this\s+document','i')])[1]"/>
      <!-- Some specs by the XHTML2 WG use h1 after the status section
      h2. Thus the following code calculates the status section first
      by looking at all nodes following the status h2 that are not
      h2 (or with an h2 descendant when inside a div) AND whose immediately
      preceding h2 sibling is the status h2. The search is complicated by
      the case where the element that "ends" the status section is an h1.
      So the search excludes nodes following the status h2 that are themselves
      h1 (or descendant is an h1) AND that have a preceding h1 that
      is not the same as the h1 that precedes the status h2. Meanwhile,
      the algorithm is designed to include any h3, h4, etc. that follow
      the h2 (read: subsections of the status section) up to the next h2|h1.
      -->
      <xsl:copy-of select="$sotdH2/following-sibling::node()[(preceding-sibling::html:h2[1] is $sotdH2) and (preceding::html:h1[1] is $sotdH2/preceding::html:h1[1]) and not(descendant-or-self::html:h2 or descendant-or-self::html:h1)]"/>
    </xsl:if>
  </xsl:function>

  <xsl:variable name="statussection" select="trd:getStatusSection()" as="node()*"/>

  <xsl:function name="trd:getAbstract">
    <xsl:variable name="abstractH2" select="($trd:body//html:h2[matches(normalize-space(.),'^\s*abstract\s*$','i')])[1]"/>
    <xsl:copy-of select="$abstractH2/following-sibling::node()[(preceding-sibling::html:h2[1] is $abstractH2) and not(descendant-or-self::html:h2)]"/>
  </xsl:function>

  <!-- Booleans about document types -->

  <xsl:function name="trd:isWD" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='WD'"/>
  </xsl:function>

  <xsl:template name="trd:isLastCall">
    <xsl:if test="trd:isLastCall()">yes</xsl:if>
  </xsl:template>

  <xsl:function name="trd:isLastCall" as="xs:boolean">
    <xsl:value-of select="trd:isWD() and (matches(trd:getStatusSubtitle(),'Last\sCall\sWorking\sDraft') or matches(trd:getStatusSubtitle(),'First\sPublic\sand\sLast\sCall\sWorking\sDraft') or matches($status-as-string,'[Ll]ast\s+[Cc]all'))"/>
  </xsl:function>

  <xsl:function name="trd:isPR" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='PR'"/>
  </xsl:function>

  <xsl:function name="trd:isPER" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='PER'"/>
  </xsl:function>

  <xsl:function name="trd:isCR" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='CR'"/>
  </xsl:function>

  <xsl:function name="trd:isREC" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='REC'"/>
  </xsl:function>

  <xsl:template name="trd:isFirstPublicWorkingDraft">
    <xsl:if test="trd:isFirstPublicWorkingDraft()">yes</xsl:if>
  </xsl:template>

  <xsl:function name="trd:isFirstPublicWorkingDraft" as="xs:boolean">
    <xsl:value-of select="trd:isWD() and (matches(trd:getStatusSubtitle(),'First\sPublic\sWorking\sDraft') or matches(trd:getStatusSubtitle(),'First\sPublic\sand\sLast\sCall\sWorking\sDraft') or matches($status-as-string,'[Ff]irst\s+[Pp]ublic\s+[Ww]orking\s+[Dd]raft'))"/>
  </xsl:function>

  <xsl:function name="trd:isNOTE" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='NOTE'"/>
  </xsl:function>

  <xsl:function name="trd:isWGNOTE" as="xs:boolean">
    <xsl:value-of select="trd:isNOTE() and matches(trd:getStatusSubtitle(),'Working\sGroup','i')"/>
  </xsl:function>

  <xsl:function name="trd:isIGNOTE" as="xs:boolean">
    <xsl:value-of select="trd:isNOTE() and matches(trd:getStatusSubtitle(),'Interest\sGroup','i')"/>
  </xsl:function>

  <xsl:function name="trd:isCGNOTE" as="xs:boolean">
    <xsl:value-of select="trd:isNOTE() and matches(trd:getStatusSubtitle(),'Coordination\sGroup','i')"/>
  </xsl:function>

  <xsl:function name="trd:isSubmission" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='SUBM'"/>
  </xsl:function>

  <xsl:function name="trd:isTeamSubmission" as="xs:boolean">
    <xsl:value-of select="trd:isSubmission() and matches(trd:getStatusSubtitle(),'Team','i')"/>
  </xsl:function>

  <xsl:function name="trd:isMemberSubmission" as="xs:boolean">
    <xsl:value-of select="trd:isSubmission() and matches(trd:getStatusSubtitle(),'Member','i')"/>
  </xsl:function>

  <xsl:function name="trd:isXGR" as="xs:boolean">
    <xsl:value-of select="trd:getShortStatus()='XGR'"/>
  </xsl:function>

  <xsl:variable name="status-as-string">
    <xsl:variable name="tmp">
      <xsl:value-of select="$statussection"/>
    </xsl:variable>
    <xsl:value-of select="normalize-space($tmp)"/>
  </xsl:variable>

  <xsl:function name="trd:statusstr" as="xs:boolean">
    <xsl:param name="str" as="xs:string"/>
    <xsl:value-of select="matches($status-as-string,$str)"/>
  </xsl:function>

  <!-- Patent policy related -->

  <xsl:template name="trd:isCallForExclusion">
    <xsl:if test="trd:isCallForExclusion()">yes</xsl:if>
  </xsl:template>

  <xsl:function name="trd:isCallForExclusion" as="xs:boolean">
    <xsl:value-of select="trd:statusstr('[Cc]all\s+[Ff]or\s+[Ee]xclusion')"/>
  </xsl:function>

  <xsl:template name="trd:isW3CPatentPolicy">
    <xsl:if test="trd:isW3CPatentPolicy()">yes</xsl:if>
  </xsl:template>

  <xsl:function name="trd:isW3CPatentPolicy" as="xs:boolean">
    <xsl:value-of select="trd:statusstr('W3C\s+[Pp]atent\s+[Pp]olicy')"/>
  </xsl:function>

  <xsl:template name="trd:is5February2004">
    <xsl:if test="trd:is5February2004()">yes</xsl:if>
  </xsl:template>

  <xsl:function name="trd:is5February2004" as="xs:boolean">
    <xsl:value-of select="trd:statusstr('5\s+February\s+2004')"/>
  </xsl:function>

  <xsl:function name="trd:isNotTargetingRec" as="xs:boolean">
    <xsl:value-of select="trd:statusstr('[Tt]he\s+((group\s+does)|(groups\s+do))\s+not\s+expect\s+((this\s+document\s+to\s+become\s+a\s+W3C\s+Recommendation)|(these\s+documents\s+to\s+become\s+W3C\s+Recommendations))')"/>
  </xsl:function>

  <xsl:template name="trd:Informative">
    <xsl:if test="trd:isInformative()">yes</xsl:if>
  </xsl:template>

  <xsl:function name="trd:isInformative" as="xs:boolean">
    <xsl:value-of select="trd:statusstr('is\s+informative\s+only')"/>
  </xsl:function>

  <xsl:template name="trd:underW3CPatentPolicy">
    <xsl:if test="trd:underW3CPatentPolicy()">yes</xsl:if>
  </xsl:template>

  <xsl:function name="trd:underW3CPatentPolicy" as="xs:boolean">
    <xsl:value-of select="trd:isW3CPatentPolicy() and
  			   trd:is5February2004() and
			   not(trd:isNotTargetingRec())"/>
  </xsl:function>

  <xsl:template name="trd:underCPP">
    <xsl:if test="trd:underCPP()">yes</xsl:if>
  </xsl:template>
			  
  <xsl:function name="trd:underCPP" as="xs:boolean">
    <xsl:value-of select="exists($statussection//html:a[matches(@href,'patent-practice|05-pp-transition')])"/>
  </xsl:function>

  <xsl:template name="trd:getDate">
    <xsl:value-of select="trd:getDate()"/>
  </xsl:template>

  <!-- Note: Some specs use DD Month, YYYY. That syntax is
  not pubrules compliant and so is rejected here -->

  <!-- When a document has been edited in place, there may be two
       dates in the H2; this regexp (and ones in other similar
       functions) returns the first one only -->

  <xsl:function name="trd:getDate">
    <xsl:if test="$statusH2!=''">
      <xsl:analyze-string select="normalize-space($statusH2)" 
			  regex=".*?(\d{{1,2}})\s({$monthsre})\s([0-9]{{4}}).*">
	<xsl:matching-substring>
	  <xsl:value-of select="regex-group(1)"/>
	  <xsl:text> </xsl:text>
	  <xsl:value-of select="regex-group(2)"/>
	  <xsl:text> </xsl:text>
	  <xsl:value-of select="regex-group(3)"/>
	</xsl:matching-substring>
	<xsl:non-matching-substring>
	  <xsl:message>
	    Warning! Did not find a date in the status H2.
	  </xsl:message>
	</xsl:non-matching-substring>
      </xsl:analyze-string>
    </xsl:if>
  </xsl:function>

  <xsl:template name="trd:getNumericDate">
    <xsl:value-of select="trd:getNumericDate()"/>
  </xsl:template>
  
  <xsl:function name="trd:getNumericDate">
    <xsl:value-of select="trd:getH2DateAux(1)"/>
  </xsl:function>

  <!-- Like trd:getNumericDate but returns an xs:date -->
  <xsl:function name="trd:getXSDate" as="xs:date">
    <xsl:value-of select="trd:getH2DateAux(2)"/>
  </xsl:function>

  <xsl:function name="trd:getH2DateAux">
    <xsl:param name="type" as="xs:integer"/>
    <!-- type=1 (num), type=2 (xs:date) -->
    <xsl:variable name="res">
      <xsl:if test="$statusH2!=''">
	<xsl:analyze-string select="normalize-space($statusH2)" 
			    regex=".*?(\d{{1,2}})\s({$monthsre})\s([0-9]{{4}}).*">
	  <xsl:matching-substring>
	    <xsl:number value="regex-group(3)" format="0001"/>
	    <xsl:text>-</xsl:text>
	    <xsl:number value="index-of($months, regex-group(2))" format="01"/>
	    <xsl:text>-</xsl:text>
	    <xsl:number value="regex-group(1)" format="01"/>
	  </xsl:matching-substring>
	  <xsl:non-matching-substring>
	    <xsl:message>
	      Warning! Did not find a date in the status H2.
	    </xsl:message>
	  </xsl:non-matching-substring>
	</xsl:analyze-string>
      </xsl:if>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="normalize-space($res)=''">
	<xsl:message>
	  Warning! No date found, returning bogus date.
	  <xsl:value-of select="trd:builddate($type, '0001-01-01')"/>
	</xsl:message>
	<xsl:value-of select="trd:builddate($type, '0001-01-01')"/>
      </xsl:when>
      <xsl:otherwise>
	<xsl:value-of select="trd:builddate($type, $res)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>
  
  <xsl:function name="trd:builddate">
    <xsl:param name="type" as="xs:integer"/>
    <xsl:param name="value"/>
    <xsl:choose>
      <xsl:when test="$type=1">
	<xsl:value-of select="translate($value,'-','')"/>
      </xsl:when>
      <xsl:when test="$type=2">
	<xsl:value-of select="xs:date($value)"/>
      </xsl:when>
      <xsl:otherwise>
	<xsl:message>
	  Warning! Unknown type in trd:builddate; returning string.
	</xsl:message>
	<xsl:value-of select="$value"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>
  
  <xsl:variable name="months" select="'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'"/>

  <xsl:variable name="monthsre" select="'January|February|March|April|May|June|July|August|September|October|November|December'"/>

  <!-- Note: included title[1] just in case even though two titles in the
  head is not permitted. However, tidy capable of putting a second title
  in the head. -->
  <xsl:function name="trd:getTitle">
    <xsl:param name="root"/>
    <xsl:value-of select="normalize-space($root//html:head/html:title[1])" />
  </xsl:function>


  <xsl:template name="trd:getTitle">
    <xsl:value-of select="trd:getTitle(root())"/>
  </xsl:template>

  <xsl:function name="trd:getShortNameFromDated">
    <xsl:param name="uri"/>
    <xsl:analyze-string select="normalize-space($uri)" 
			regex=".*/[^\-]+\-(.*)\-\d{{8}}/?$">
      <xsl:matching-substring>
	<xsl:value-of select="regex-group(1)"/>
      </xsl:matching-substring>
    </xsl:analyze-string>
  </xsl:function>

  <xsl:function name="trd:getShortNameFromUndated">
    <xsl:param name="uri"/>
    <xsl:analyze-string select="normalize-space($uri)" 
			regex=".*/([^/]+)/?$">
      <xsl:matching-substring>
	<xsl:value-of select="regex-group(1)"/>
      </xsl:matching-substring>
    </xsl:analyze-string>
  </xsl:function>

  <xsl:variable name="versionblock" select="$trd:divHead//html:dl"/>

  <xsl:function name="trd:VersionURIAux">
    <xsl:param name="m"/>
    <!-- Note: Some specs have multiple <dt> that include the same keyword. Just take the first one -->
    <xsl:variable name="dt" select="$versionblock/html:dt[matches(normalize-space(.),'version','i') and matches(normalize-space(.),$m,'i')][1]"/>
    <!-- Note: Some specs list multiple previous versions. Look for the most recent date and take that one -->
    <xsl:variable name="dds" select="$dt/following-sibling::html:dd[preceding-sibling::html:dt[1] is $dt]" as="node()*"/>
    <xsl:choose>
      <xsl:when test="count($dds//html:a) eq 0">
	<xsl:message>
	  Error: No URI found for keyword <xsl:value-of select="$m"/>
	</xsl:message>
      </xsl:when>
      <xsl:when test="count($dds//html:a) eq 1">
	<xsl:value-of select="normalize-space($dds//html:a/@href)"/>
      </xsl:when>
      <xsl:otherwise>
	<xsl:message>
	  Warning: Found multiple URIs of this version type, looking for the most recent one.
	</xsl:message>
	<xsl:variable name="vuris" select="$dds//html:a/@href" as="xs:string*"/>
	<xsl:variable name="dates" as="xs:integer*">
	  <xsl:for-each select="$vuris">
	    <xsl:choose>
	      <xsl:when test="not(matches(.,'.+\-(\d{8})'))">
		<xsl:message>
		  Error: Found URI that does not match YYYYMMDD/? - <xsl:value-of select="."/>
		</xsl:message>
	      </xsl:when>
	      <xsl:otherwise>
		<xsl:value-of select="xs:integer(replace(.,'.+\-(\d{8})/?','$1'))"/>
	      </xsl:otherwise>
	    </xsl:choose>
	  </xsl:for-each>
	</xsl:variable>
	<xsl:variable name="max" select="max($dates)"/>
	<!-- Wish I knew how to get the Nth element of the sequence that matches a pattern, but don't think index-of supports that -->
	<xsl:variable name="getmax">
	  <xsl:for-each select="$vuris">
            <xsl:if test="$max">
	      <xsl:if test="matches(.,xs:string($max))">
	        <xsl:value-of select="."/>
              </xsl:if>
            </xsl:if>
            <!-- if no dated uris have been found, take the first TR uri-->
            <!-- this is the case for multiple latest version uris (see
                 http://www.w3.org/TR/unicode-xml/ -->
            <xsl:if test="not($max)">
              <xsl:if test="matches(.,'http://www.w3.org/TR/.+')">
	        <xsl:value-of select="."/>
              </xsl:if>
            </xsl:if>
	  </xsl:for-each>
	</xsl:variable>
	<xsl:value-of select="normalize-space(string-join($getmax,''))"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="trd:latestVersionURI">
    <xsl:value-of select="trd:VersionURIAux('latest')"/>
  </xsl:function>

  <xsl:function name="trd:thisVersionURI">
    <xsl:value-of select="trd:VersionURIAux('this')"/>
  </xsl:function>

  <xsl:function name="trd:previousVersionURI">
    <xsl:value-of select="trd:VersionURIAux('previous')"/>
  </xsl:function>

  <xsl:function name="trd:editorDraftURI">
    <!-- Note: Some specs have multiple <dt> that include the same keyword. Just take the first one -->
    <xsl:variable name="dt" select="$versionblock/html:dt[matches(normalize-space(.),'editor','i') and matches(normalize-space(.),'draft','i')][1]"/>
    <!-- Note: Some specs list multiple previous versions. Look for the most recent date and take that one -->
    <xsl:variable name="dds" select="$dt/following-sibling::html:dd[preceding-sibling::html:dt[1] is $dt]" as="node()*"/>
    <xsl:value-of select="$dds"/>
  </xsl:function>

  <xsl:template name="trd:getVersionURI">
    <xsl:param name="which"/>
    <xsl:choose>
      <xsl:when test="$which='latest'"><xsl:value-of select="trd:latestVersionURI()"/></xsl:when>
      <xsl:when test="$which='this'"><xsl:value-of select="trd:thisVersionURI()"/></xsl:when>
      <xsl:when test="$which='previous'"><xsl:value-of select="trd:previousVersionURI()"/></xsl:when>
      <xsl:otherwise>
	<xsl:message>
	  Warning: Unknown value of "which" in trd:getVersionURI.
	</xsl:message>
	UnknownValueofWhich
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="trd:hasNewShortname">
    <xsl:if test="trd:hasNewShortname()">yes</xsl:if>
  </xsl:template>
  
  <xsl:function name="trd:hasNewShortname" as="xs:boolean">
    <xsl:value-of select="trd:previousVersionURI()!='' and
			  (trd:getShortNameFromDated(trd:previousVersionURI()) ne
                          trd:getShortNameFromUndated(trd:latestVersionURI()))"/>
  </xsl:function>


  <!-- Looks for a <dt></dt> containing either "Editor" or "Author" -->

  <xsl:template name="trd:getEditorsSectionName">
    <xsl:value-of select="trd:getEditorsSectionName()"/>
  </xsl:template>

  <!-- The regexp allows for (Author|Editor)s?(versioninfo)?:? -->
  <!-- That is: optional "s" and ":" -->
  <!-- Allows for version information in parens -->
  <!-- It is also used in trd:getEditorsList -->

  <xsl:function name="trd:edregexp" as="xs:string">
    <xsl:param name="v"/>
    <xsl:value-of select="concat('^',$v,'(s?)(\s+\([^)]+\)\s*)?(:?)$')"/>
  </xsl:function>

  <xsl:function name="trd:getEditorsSectionName">
    <xsl:choose>
      <xsl:when test="$trd:divHead//html:dl/html:dt[matches(normalize-space(),trd:edregexp('Editor'))]">Editor</xsl:when>
      <xsl:when test="$trd:divHead//html:dl/html:dt[matches(normalize-space(),trd:edregexp('Author'))]">Author</xsl:when>
    </xsl:choose>
  </xsl:function>

  <!-- BNF for editor information:
       
       EditorsList ::= '<dd>' EditorInfo ['<br/>' EditorInfo ]+ '</dd>' 
                       |
		       ['<dd>' EditorInfo '</dd>' ]+
       EditorInfo  ::= EditorName [Tokens] [ EditorMailbox ]
       Tokens      ::= stuff that is likely to include
                       '(' | ',' | '-' | '&lt;' 

      Note that this code does not look for a simple
      comma-separated list of editor names.

      The code below does not worry about whether there is a mix
      of markup, namely N gt 1 <dd> elements at least one of
      which also includes <br>-separated editor information.
  -->

  <xsl:template name="trd:getEditorsList">
    <xsl:variable name="esn" select="trd:getEditorsSectionName()"/>
    <xsl:choose>
      <xsl:when test="normalize-space($esn)=''">
	<xsl:message>
	  Warning! No editors or authors section name found!
	</xsl:message>
      </xsl:when>
      <xsl:otherwise>
	<xsl:for-each select="$trd:divHead//html:dl/html:dt[matches(normalize-space(),trd:edregexp($esn))]">
	  <xsl:variable name="sect" select="."/>
	  <xsl:variable name="dds" select="$sect/following-sibling::html:dd[preceding-sibling::html:dt[1] is $sect]"/>
	  <xsl:variable name="editorseq" as="xs:string*">
	    <xsl:apply-templates mode="editor" select="$dds"/>
	  </xsl:variable>
	  <xsl:variable name="mboxseq" as="xs:string*">
	    <xsl:apply-templates mode="mbox" select="$dds"/>
	  </xsl:variable>
	  <xsl:for-each select="distinct-values($editorseq)">
	    <xsl:variable name="en" select="."/>
	    <xsl:call-template name="trd:formatEditorName">
	      <xsl:with-param name="trd:EditorName" select="normalize-space(.)"/>
	      <xsl:with-param name="trd:EditorMailbox" select="normalize-space($mboxseq[index-of($editorseq,$en)[1]])"/>
	    </xsl:call-template>
	  </xsl:for-each>
	</xsl:for-each>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template match="html:dd" mode="mbox" as="xs:string*">
    <xsl:for-each-group select="node()" group-starting-with="html:br">
      <xsl:variable name="eistr">
	<xsl:value-of select="current-group()"/>
      </xsl:variable>
      <xsl:choose>
	<!-- Could do this with non-matching-substring instead,
	but I'm more comfortable checking for '@' and not
	using regexps that might be imperfect -->
	<xsl:when test="contains(normalize-space($eistr),'@')">
	  <!-- Look for email addresses deliminated by space, paren, or
	       pointy brackets -->
	  <xsl:analyze-string select="normalize-space($eistr)" regex=".*?([^\(\s&lt;]+@[^\)\s&gt;]+).*">
	    <xsl:matching-substring>
	      <xsl:value-of select="concat('mailto:',regex-group(1))"/>
	    </xsl:matching-substring>
	  </xsl:analyze-string>
	</xsl:when>
	<xsl:otherwise>
	  <!-- If no "@", then look for mailto uri -->
	  <xsl:value-of select="current-group()[@href and starts-with(@href,'mailto:')]/normalize-space(@href)"/>
	</xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="html:dd" mode="editor" as="xs:string*">
    <xsl:for-each-group select="node()" group-starting-with="html:br">
      <xsl:variable name="eistr">
	<xsl:value-of select="current-group()"/>
      </xsl:variable>
      <!-- The "." is for Jr. 
           The [0-9] is for the case of "Don Eastlake 3rd"
           The '-' is for the case of Peter Patel-Schneider
	   I did not include "," (which would be appropriate
	   before Jr.) but would likely be ambiguous.
	   -->
      <xsl:analyze-string select="normalize-space($eistr)" regex="^((\p{{L}}|[0-9]|\-|\.|\s)+).*">
	<xsl:matching-substring>
	  <xsl:value-of select="regex-group(1)"/>
	  <xsl:if test="matches(regex-group(1),'acknowledgments','i')">
	    <xsl:message>
	      Warning! There seems to be a line about acknowledgments; this
              may require additional work to identify authors.
	    </xsl:message>
	  </xsl:if>
	</xsl:matching-substring>
	<xsl:non-matching-substring>
	  <xsl:message>
	    Warning: No editor name found in <xsl:value-of select="$eistr"/>
	  </xsl:message>
	  NoEditorNameFound
	</xsl:non-matching-substring>
      </xsl:analyze-string>
    </xsl:for-each-group>
  </xsl:template>

<!-- Default template for formatting editor name; can be overridden
     by user and is overridden when generating rdf -->

<xsl:template name="trd:formatEditorName">
  <xsl:param name="trd:EditorName"/>
  <xsl:param name="trd:EditorMailbox"/>
  <xsl:value-of select="$trd:EditorName"/>,
</xsl:template>

<xsl:function name="trd:flexibleURIComp" as="xs:boolean">
  <xsl:param name="rel"/>    <!-- The @href value found -->
  <xsl:param name="abs"/>    <!-- What we are looking for -->
  <xsl:param name="base"/>
  <xsl:choose>
    <xsl:when test="contains($rel,'#')">
      <xsl:value-of select="trd:flexibleURIComp(substring-before($rel,'#'),$abs,$base)"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="fullrel" select="resolve-uri($rel,$base)"/>
      <!-- Do _not_ allow equivlaence of abs with fullrel with
           appended trailing slash; that is done as a separate call -->
      <xsl:choose>
	<xsl:when test="$fullrel=$abs">true</xsl:when>
	<xsl:when test="concat($fullrel,'.html')=$abs">true</xsl:when>
	<xsl:when test="$fullrel=concat($abs,'.html')">true</xsl:when>
	<xsl:when test="ends-with($abs,'/')">
	  <xsl:choose>
	    <!-- I don't expect case where the reference URI we use
		 ends with Overview.html or index.html -->
	    <xsl:when test="$fullrel=concat($abs,'Overview.html')">true</xsl:when>
	    <xsl:when test="$fullrel=concat($abs,'index.html')">true</xsl:when>
	    <xsl:otherwise>false</xsl:otherwise>
	  </xsl:choose>
	</xsl:when>
	<xsl:otherwise>false</xsl:otherwise>
      </xsl:choose>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<!-- 
     Given a sequence of URIs ($seq), return the subsequence
     of URIs found in the Status Section (duplicates removed,
     and fragment identifiers removed. Uses somewhat loose
     URI comparison.
-->

<xsl:function name="trd:getURIs" as="xs:string*">
  <xsl:param name="seq" as="node()*"/>
  <xsl:variable name="base">http://www.w3.org/</xsl:variable>
  <xsl:variable name="results" as="xs:string*">
    <xsl:for-each select="$seq">
      <xsl:variable name="home" select="normalize-space(.)"/>
      <xsl:variable name="urires" select="resolve-uri(($statussection//html:a[@href and trd:flexibleURIComp(normalize-space(@href),$home,$base)])[1]/normalize-space(@href),$base)"/>
      <xsl:choose>
	<xsl:when test="$urires!=''">
	  <!-- Remove any fragid at the end -->
	  <xsl:value-of select="replace($urires,'([^#]+)(#.+)?','$1')"/>
	</xsl:when>
	<xsl:otherwise>
	  <!-- Try again by adding trailing slash to found @href
	  values to see if one matches -->
	  <xsl:variable name="urires2" select="resolve-uri(($statussection//html:a[@href and not(ends-with(normalize-space(@href),'/')) and trd:flexibleURIComp(concat(normalize-space(@href),'/'),$home,$base)])[1]/concat(normalize-space(@href),'/'),$base)"/>
	  <xsl:value-of select="replace($urires2,'([^#]+)(#.+)?','$1')"/>
	</xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:variable>
  <xsl:copy-of select="distinct-values($results)[normalize-space(.)!=('')]"/>
</xsl:function>

<!-- Boo! These sequences should be comma-separated, not formatted
     with an ending comma, but I'm doing this for compatibility -->

<xsl:template name="trd:getActivity">
  <!-- Handle Activity home pages and activity statements separately
   (for the case where RDF is being generated, e.g.) -->
  <xsl:for-each select="trd:getURIs($public-groups//rdf:Description[rdf:type[@rdf:resource='http://www.w3.org/2001/04/roadmap/org#Activity']]/contact:homePage/@rdf:resource)">
    <xsl:call-template name="trd:formatActivityHP">
      <xsl:with-param name="uri" select="."/>
    </xsl:call-template>
  </xsl:for-each>
  <xsl:for-each select="trd:getURIs($public-groups//rdf:Description[rdf:type[@rdf:resource='http://www.w3.org/2001/04/roadmap/org#Activity']]/org:statement/@rdf:resource)">
    <xsl:call-template name="trd:formatActivityStatement">
      <xsl:with-param name="uri" select="."/>
    </xsl:call-template>
  </xsl:for-each>
</xsl:template>

<xsl:template name="trd:formatActivityHP">
  <xsl:param name="uri"/>
  <xsl:value-of select="concat($uri,', ')"/>
</xsl:template>

<xsl:template name="trd:formatActivityStatement">
  <xsl:param name="uri"/>
  <xsl:value-of select="concat($uri,', ')"/>
</xsl:template>

<!-- One possible improvement: look at ipp data too for wg homes (to avoid
    false positives on wg home pages...but be careful since
    ipp also relies on tr.rdf... -->

<!-- Note: This code assumes that there is only one public home page
    per group in $pubrules-copyright. This means that if there is
    a second dd with another URI, it is ignored by this code. -->

<xsl:template name="trd:getWorkingGroup">
  <xsl:variable name="homeuris" select="trd:getURIs($public-groups//rdf:Description[rdf:type[matches(@rdf:resource,'Group|WG','i')]]/contact:homePage/@rdf:resource|$pubrules-copyright//html:dd[preceding-sibling::html:dt[1][matches(.,'Group|WG','i')] and matches(.,'public','i')]/html:a/@href)" as="xs:string*"/>
  <xsl:choose>
    <xsl:when test="count($homeuris) eq 0">
      <xsl:message>
	Warning! No group home page found.
      </xsl:message>
    </xsl:when>
    <xsl:otherwise>
      <xsl:for-each select="$homeuris">
	<xsl:call-template name="trd:formatWorkingGroupHP">
	  <xsl:with-param name="uri" select="."/>
	</xsl:call-template>
      </xsl:for-each>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

  <xsl:template name="trd:formatWorkingGroupHP">
    <xsl:param name="uri"/>
    <xsl:value-of select="concat($uri,', ')"/>
  </xsl:template>

<!-- How does this function fail when it finds something that
looks like a date in the regexp but is not? how does index-of fail? -->

<xsl:template name="trd:getFeedbackDueDate">
  <xsl:value-of select="trd:getFeedbackDueDate()"/>
</xsl:template>

<xsl:function name="trd:getFeedbackDueDate">
  <xsl:if test="trd:isLastCall() or trd:isPR() or trd:isPER() or trd:isCR()">
    <xsl:variable name="low_bound" select="trd:getXSDate()"/>
    <xsl:variable name="high_bound" select="$low_bound + xs:yearMonthDuration('P1Y')"/>
    <xsl:variable name="results" as="xs:string*">
      <xsl:analyze-string select="$status-as-string"
			  regex="(\d{{1,2}})\s+({$monthsre})\s+([0-9]{{4}})">
	<xsl:matching-substring>
	  <xsl:variable name="res">
	    <xsl:number value="regex-group(3)" format="0001"/>
	    <xsl:text>-</xsl:text>
	    <xsl:number value="index-of($months, regex-group(2))" format="01"/>
	    <xsl:text>-</xsl:text>
	    <xsl:number value="regex-group(1)" format="01"/>
	  </xsl:variable>
	  <xsl:if test="(xs:date($res) gt $low_bound) and (xs:date($res) le $high_bound)">
	    <!-- could make this xs:date but not sure yet. -->
	    <xsl:value-of select="$res"/>
	  </xsl:if>
	</xsl:matching-substring>
      </xsl:analyze-string>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="empty($results)">
	<xsl:message>
	  Warning: No dates found by trd:getFeedbackDueDate.
	</xsl:message>
      </xsl:when>
      <xsl:otherwise>
	<xsl:variable name="distinctdates" 
		      select="distinct-values($results)[normalize-space(.)!=('')]"
		      as="xs:string*"/>
	<xsl:if test="count($distinctdates) gt 1">
	  <xsl:message>
	    Warning: Two or more dates found by trd:getFeedbackDueDate;
	    choosing the minimum of <xsl:value-of select="string-join($distinctdates,', ')"/>.
	    <xsl:if test="trd:isCR()">
	     Note that for a CR, one date is likely to be
	     a feedback deadline and the other the date by
	     which the group expects to have implementation
	     experience.
	    </xsl:if>
	  </xsl:message>
	</xsl:if>
	<xsl:value-of select="min($distinctdates)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:if>
</xsl:function>

<xsl:template name="trd:getErrata">
  <xsl:value-of select="trd:getErrata()"/>
</xsl:template>

<xsl:function name="trd:getErrata">
  <!-- Note that pubrules REQUIRES a strong element inside the a element -->
  <xsl:if test="trd:isREC()">
    <xsl:call-template name="trd:dlurlaux">
      <xsl:with-param name="hrefs" select="$trd:divHead//html:dl/following-sibling::html:p[1]//html:a[html:strong[normalize-space(.)='errata']]/normalize-space(@href)"/>
      <xsl:with-param name="errval">MoreThanOneErrataURIFound</xsl:with-param>
      <xsl:with-param name="msg">errata</xsl:with-param>
    </xsl:call-template>
  </xsl:if>
</xsl:function>

<xsl:template name="trd:getTranslations">
  <xsl:value-of select="trd:getTranslations()"/>
</xsl:template>

<xsl:function name="trd:getTranslations">
  <!-- Note that pubrules RECOMMENDS (for translation URIs)
       a strong element inside the a element; this test does not
       require html:strong. And the position of the paragraph
       is not specified; recommended is second after dl -->
  <xsl:if test="trd:isREC()">
    <xsl:call-template name="trd:dlurlaux">
      <xsl:with-param name="hrefs" select="$trd:divHead//html:dl/following-sibling::html:p//html:a[normalize-space(.)='translations']/normalize-space(@href)"/>
      <xsl:with-param name="errval">MoreThanOneTranslationsURIFound</xsl:with-param>
      <xsl:with-param name="msg">translations</xsl:with-param>
    </xsl:call-template>
  </xsl:if>
</xsl:function>

<xsl:template name="trd:getImplReport">
  <xsl:value-of select="trd:getImplReport()"/>
</xsl:template>

<xsl:function name="trd:getImplReport">
  <xsl:if test="trd:isREC() or trd:isCR() or trd:isPR() or trd:isPER()">
    <xsl:call-template name="trd:dlurlaux">
      <xsl:with-param name="hrefs" select="$statussection//html:a[matches(normalize-space(.),'implementation|interoperability','i')]/normalize-space(@href)"/>
      <xsl:with-param name="errval">MoreThanOneImplURIFound</xsl:with-param>
      <xsl:with-param name="msg">implementation report</xsl:with-param>
    </xsl:call-template>
  </xsl:if>
</xsl:function>

<xsl:template name="trd:dlurlaux">
  <xsl:param name="hrefs"/>
  <xsl:param name="errval"/>
  <xsl:param name="msg"/>
  <xsl:variable name="distinct" select="distinct-values($hrefs)"/>
  <xsl:choose>
    <xsl:when test="count($distinct) gt 1">
      <xsl:message>
	Warning: Found more than one distinct URI for <xsl:value-of select="$msg"/>.
      </xsl:message>
      <xsl:value-of select="$errval"/>
    </xsl:when>
    <xsl:when test="count($distinct) eq 1">
      <xsl:value-of select="normalize-space($distinct)"/>
    </xsl:when>
  </xsl:choose>
</xsl:template>

<xsl:function name="trd:getProcessRevision" as="xs:string*">
  <!-- Just return a URI or nil if not found -->
  <xsl:value-of select="normalize-space($statussection//html:a[@id='w3c_process_revision']/@href)"/>
</xsl:function>

<xsl:function name="trd:getProcessParagraph" as="xs:string*">
  <xsl:variable name="paranode" select="$statussection[html:a[@id='w3c_process_revision']]"/>
  <xsl:choose>
    <xsl:when test="count($paranode)=0">
      <xsl:message>
	No element found in the status with an anchor with id="w3c_process_revision.
      </xsl:message>
    </xsl:when>
    <xsl:when test="local-name($paranode)='p'">
      <xsl:value-of select="$paranode"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:message>
	Found id=w3c_process_revision but not within a p parent.
      </xsl:message>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="trd:validProcessRevision" as="xs:boolean">
  <xsl:param name="procrev"/>
  <xsl:choose>
    <xsl:when test="matches($procrev,'http://www.w3.org/2005/10/Process-20051014/')">true</xsl:when>
    <xsl:when test="matches($procrev,'http://www.w3.org/2015/Process-20150901/')">true</xsl:when>
    <xsl:otherwise>false</xsl:otherwise>
  </xsl:choose>
</xsl:function>

<xsl:function name="trd:process2005" as="xs:boolean">
  <xsl:value-of select="matches(trd:getProcessRevision(),'http://www.w3.org/2005/10/Process-20051014/')"/>
</xsl:function>

<xsl:function name="trd:process2015" as="xs:boolean">
  <xsl:value-of select="matches(trd:getProcessRevision(),'http://www.w3.org/2015/Process-20150901/')"/>
</xsl:function>

<xsl:function name="trd:processRevisionRequired" as="xs:boolean">
  <xsl:param name="publicationdate" as="xs:date"/>
  <!--
  Prior to the announcement of the 2014 Process, tech reports
  were not required to include explicit process revision information.
  Update 2015/09/01: Process 2015 replaces process 2014
  -->
  <xsl:value-of select="$publicationdate ge xs:date('2014-09-02')"/>
</xsl:function>

</xsl:stylesheet>
