On 07/14/2011 01:57 AM, major dennis bloodnok wrote:
trying to output a ditamap that contains 104 topicref links. running ditac with 
the following command:

$ ditac -p number all -p chain-pages both -p chain-topics yes out/_.html 
esm-wadl.ditamap

after churning for a while, it throws the following error:

ditac: ERROR: fatal error reported by the XSLT engine: A sequence of more than one item is 
not allowed as the result of function u:currentChunk() 
(<ditac:chunk/>,<ditac:chunk/>, ...) ; SystemID: 
file:/usr/local/ditac/xsl/common/ditacUtil.xsl; Line#: 51; Column#: -1
ditac: ERROR: cannot transform "/Users/jeeeem/Documents/breakup/out/admin.ditac" to 
"/Users/jeeeem/Documents/breakup/out/admin.html" using file:/usr/local/ditac/xsl/xhtml/xhtml.xsl: A 
sequence of more than one item is not allowed as the result of function u:currentChunk() 
(<ditac:chunk/>,<ditac:chunk/>, ...)

using the built-in xerces engine, i can get output from these files so it's 
apparently not my source files.


Thank you for sending us a tiny subset of your data. This allowed us to easily reproduce the bug.

This bug can be described as follows:
---
A map referencing topics having IDs and/or file basenames starting with the same prefix (for example, "foo.dita", "foo.bar.dita", "foo.bar.wiz.dita" all start with the same "foo." prefix) caused ditac to fail with the following error: "A sequence of more than one item is not allowed as the result of function u:currentChunk()...".
---

The bug fix will be found in ditac v2.0.4, which should be released within a couple of weeks.

Meanwhile, you can patch your copy of ditac v2.0.3 by replacing

ditac_install_dir/xsl/common/commonUtil.xsl
ditac_install_dir/xsl/common/ditacUtil.xsl

by the two, attached, .xsl files.
<?xml version="1.0" encoding="UTF-8"?>
<!--
| Copyright (c) 2009-2011 Pixware SARL. All rights reserved.
|
| Author: Hussein Shafie
|
| This file is part of the XMLmind DITA Converter project.
| For conditions of distribution and use, see the accompanying LEGAL.txt file.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                xmlns:xs="http://www.w3.org/2001/XMLSchema";
                xmlns:u="http://www.xmlmind.com/namespace/ditac";
                xmlns:Image="java:com.xmlmind.ditac.xslt.Image"
                exclude-result-prefixes="xs u Image"
                version="2.0">

  <!-- basename ========================================================== -->

  <xsl:function name="u:basename" as="xs:string">
    <xsl:param name="path" as="xs:string"/>

    <xsl:sequence select="if ($path != '') then
                              tokenize($path, '/')[last()]
                          else 
                              ''" />
  </xsl:function>

  <!-- extension ========================================================= -->

  <xsl:function name="u:extension" as="xs:string">
    <xsl:param name="path" as="xs:string"/>

    <xsl:variable name="basename" select="u:basename($path)" />

    <xsl:sequence select="if ($basename != '') then
                              tokenize($basename, '\.')[last()]
                          else 
                              ''" />
  </xsl:function>

  <!-- indexOfNode ======================================================= -->

  <xsl:function name="u:indexOfNode" as="xs:integer*">
    <xsl:param name="nodeSequence" as="node()*"/>
    <xsl:param name="searchedNode" as="node()"/>

    <xsl:for-each select="$nodeSequence">
      <xsl:if test=". is $searchedNode">
        <xsl:sequence select="position()"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:function>

  <!-- classToElementName ================================================ -->

  <xsl:function name="u:classToElementName" as="xs:string">
    <xsl:param name="class" as="xs:string"/>

    <xsl:sequence select="tokenize(normalize-space($class), '/|\s+')[last()]"/>
  </xsl:function>

  <!-- imageWidth ======================================================== -->

  <xsl:template name="imageWidth">
    <xsl:param name="path" select="''"/>

    <xsl:sequence select="Image:getWidth(resolve-uri($path, base-uri()))"/>
  </xsl:template>

  <!-- noteType ========================================================== -->

  <xsl:template name="noteType">
    <xsl:choose>
      <xsl:when test="@type = 'other' and @othertype">
        <xsl:value-of select="normalize-space(@othertype)"/>
      </xsl:when>
      <xsl:when test="@type and @type != 'other'">
        <xsl:value-of select="@type"/>
      </xsl:when>
      <xsl:otherwise>note</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Table processing utilities ======================================== -->

  <xsl:template name="processCellContents">
    <xsl:choose>
      <xsl:when test="exists(./text()|./*)">
        <xsl:apply-templates/>
      </xsl:when>
      <xsl:otherwise>&#xA0;</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:function name="u:entryRowSpan" as="xs:integer">
    <xsl:param name="entry" as="element()"/>

    <xsl:for-each select="$entry">
      <xsl:choose>
        <!-- number() returns NaN instead of raising an error. -->
        <xsl:when test="number(@morerows) gt 0">
          <xsl:sequence select="xs:integer(@morerows) + 1"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="1"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:function>

  <xsl:function name="u:entryColSpan" as="xs:integer">
    <xsl:param name="entry" as="element()"/>

    <xsl:for-each select="$entry">
      <!-- Remember that a table can contain another table. -->
      <xsl:variable name="tgroup" 
        select="(ancestor::*[contains(@class,' topic/tgroup ')])[last()]"/>
      <xsl:variable name="colspecs" 
        select="$tgroup/*[contains(@class,' topic/colspec ')]"/>

      <xsl:variable name="namest" select="@namest"/>
      <xsl:variable name="nameend" select="@nameend"/>

      <xsl:choose>
        <xsl:when test="exists($colspecs) and 
                        exists($namest) and exists($nameend)">
          <xsl:variable name="colst" 
                        select="($colspecs[./@colname = $namest])[1]"/>
          <xsl:variable name="colend" 
                        select="($colspecs[./@colname = $nameend])[1]"/>
          
          <xsl:choose>
            <xsl:when test="exists($colst) and exists($colend)">
              <xsl:variable name="colnumst" 
                            select="u:colspecNumber($colst)"/>
              <xsl:variable name="colnumend" 
                            select="u:colspecNumber($colend)"/>

              <xsl:choose>
                <xsl:when test="$colnumend gt $colnumst">
                  <xsl:sequence select="$colnumend - $colnumst + 1"/>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:sequence select="1"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
              <xsl:sequence select="1"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="1"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:function>

  <xsl:function name="u:colspecNumber" as="xs:integer">
    <xsl:param name="colspec" as="element()"/>

    <xsl:for-each select="$colspec">
      <xsl:variable name="previousColspec" 
        select="(preceding-sibling::*[contains(@class,' topic/colspec ')])[last()]"/>

      <xsl:variable name="nextColspecNumber" as="xs:integer">
        <xsl:choose>
          <xsl:when test="exists($previousColspec)">
            <xsl:sequence select="u:colspecNumber($previousColspec) + 1"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:sequence select="1"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>

      <xsl:choose>
        <!-- number() returns NaN instead of raising an error. -->
        <xsl:when test="exists(@colnum) and 
                        (number(@colnum) ge $nextColspecNumber)">
          <xsl:sequence select="xs:integer(@colnum)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$nextColspecNumber"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:function>

  <xsl:function name="u:bodyLayout" as="xs:string*">
    <xsl:param name="body" as="element()"/>

    <xsl:for-each select="$body">
      <xsl:variable name="firstRow" 
                    select="(*[contains(@class,' topic/row ')])[1]"/>
      <xsl:sequence select="if (exists($firstRow))
                            then u:rowLayout($firstRow, 1, ())
                            else ()"/>
    </xsl:for-each>
  </xsl:function>

  <xsl:function name="u:rowLayout" as="xs:string*">
    <xsl:param name="row" as="element()"/>
    <xsl:param name="rowIndex" as="xs:integer"/>
    <xsl:param name="bodyLayout" as="xs:string*"/>

    <xsl:for-each select="$row">
      <xsl:variable name="firstEntry" 
                    select="(*[contains(@class,' topic/entry ')])[1]"/>
      <xsl:variable name="bodyLayout2" 
        select="if (exists($firstEntry))
                then u:entryLayout($firstEntry, $rowIndex, $bodyLayout)
                else ()"/>

      <xsl:variable name="nextRow" 
        select="(following-sibling::*[contains(@class,' topic/row ')])[1]"/>
      <xsl:choose>
        <xsl:when test="exists($nextRow)">
          <xsl:sequence
            select="u:rowLayout($nextRow, $rowIndex + 1, $bodyLayout2)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$bodyLayout2"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:function>

  <xsl:function name="u:entryLayout" as="xs:string*">
    <xsl:param name="entry" as="element()"/>
    <xsl:param name="rowIndex" as="xs:integer"/>
    <xsl:param name="bodyLayout" as="xs:string*"/>

    <xsl:for-each select="$entry">
      <xsl:variable name="id" select="generate-id($entry)"/>
      <xsl:variable name="rowSpan" select="u:entryRowSpan($entry)"/>
      <xsl:variable name="colSpan" select="u:entryColSpan($entry)"/>

      <xsl:variable name="explicitColspec" select="u:entryColspec(., ())"/>
      <xsl:variable name="colIndex" as="xs:integer">
        <xsl:choose>
          <xsl:when test="exists($explicitColspec)">
            <xsl:sequence select="u:colspecNumber($explicitColspec)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:variable name="previousEntry" 
              select="(preceding-sibling::*[contains(@class,' topic/entry ')])[last()]"/>
            <xsl:variable name="colIndex0" 
              select="if (exists($previousEntry))
                      then (u:entryEndColumn($previousEntry, $bodyLayout) + 1)
                      else 1"/>

            <xsl:sequence
              select="u:nextFreeColIndex($bodyLayout, $rowIndex, $colIndex0)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>

      <xsl:variable name="added"
        select="for $r in ($rowIndex to ($rowIndex + $rowSpan - 1))
                return
                  for $c in ($colIndex to ($colIndex + $colSpan - 1))
                  return concat($id, '_', $r, '_', $c)"/>

      <xsl:variable name="bodyLayout2" select="($bodyLayout, $added)"/>

      <xsl:variable name="nextEntry" 
        select="(following-sibling::*[contains(@class,' topic/entry ')])[1]"/>
      <xsl:choose>
        <xsl:when test="exists($nextEntry)">
          <xsl:sequence
            select="u:entryLayout($nextEntry, $rowIndex, $bodyLayout2)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$bodyLayout2"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:function>

  <xsl:function name="u:nextFreeColIndex" as="xs:integer">
    <xsl:param name="bodyLayout" as="xs:string*"/>
    <xsl:param name="rowIndex" as="xs:integer"/>
    <xsl:param name="colIndex" as="xs:integer"/>

    <xsl:variable name="tail"
                  select="concat('_', $rowIndex, '_', $colIndex)"/>
    <xsl:variable name="match" 
                  select="for $s in $bodyLayout
                          return
                            if (ends-with($s, $tail))
                            then $s
                            else ()"/>

    <xsl:sequence
      select="if (exists($match))
              then u:nextFreeColIndex($bodyLayout, $rowIndex, $colIndex + 1)
              else $colIndex"/>
  </xsl:function>

  <xsl:function name="u:bodyLayoutContains" as="xs:boolean">
    <xsl:param name="bodyLayout" as="xs:string*"/>
    <xsl:param name="rowIndex" as="xs:integer"/>
    <xsl:param name="colIndex" as="xs:integer"/>

    <xsl:variable name="tail"
                  select="concat('_', $rowIndex, '_', $colIndex)"/>
    <xsl:variable name="match" 
                  select="for $s in $bodyLayout
                          return
                            if (ends-with($s, $tail))
                            then $s
                            else ()"/>

    <xsl:sequence select="exists($match)"/>
  </xsl:function>

  <xsl:function name="u:entryStartColumn" as="xs:integer">
    <xsl:param name="entry" as="element()"/>
    <xsl:param name="bodyLayout" as="xs:string*"/>

    <xsl:sequence select="u:entryColumn($entry, $bodyLayout, false())"/>
  </xsl:function>

  <xsl:function name="u:entryEndColumn" as="xs:integer">
    <xsl:param name="entry" as="element()"/>
    <xsl:param name="bodyLayout" as="xs:string*"/>

    <xsl:sequence select="u:entryColumn($entry, $bodyLayout, true())"/>
  </xsl:function>

  <xsl:function name="u:entryColumn" as="xs:integer">
    <xsl:param name="entry" as="element()"/>
    <xsl:param name="bodyLayout" as="xs:string*"/>
    <xsl:param name="isEndColumn" as="xs:boolean"/>

    <xsl:variable name="id" select="generate-id($entry)"/>
    <xsl:variable name="head" select="concat($id, '_')"/>
    <xsl:variable name="cols" as="xs:integer*"
                  select="for $s in $bodyLayout
                          return
                            if (starts-with($s, $head))
                            then u:parseEntryColumn($s)
                            else ()"/>

    <xsl:variable name="uniqueCols" select="distinct-values($cols)"/>
    <xsl:variable name="sortedCols" as="xs:integer*">
      <xsl:choose>
        <xsl:when test="count($uniqueCols) gt 1">
          <xsl:perform-sort select="$uniqueCols">
            <xsl:sort select="." data-type="number"/>
          </xsl:perform-sort>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="$uniqueCols"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="empty($sortedCols)">
        <xsl:message
          terminate="yes">Internal error in u:entryColumn().</xsl:message>
      </xsl:when>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="$isEndColumn">
            <xsl:sequence select="$sortedCols[last()]"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:sequence select="$sortedCols[1]"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="u:parseEntryColumn" as="xs:integer">
    <xsl:param name="spec" as="xs:string"/>

    <xsl:variable name="split" select="tokenize($spec, '_')"/>
    <xsl:sequence select="xs:integer($split[3])"/>
  </xsl:function>

  <xsl:function name="u:entryColspec" as="element()?">
    <xsl:param name="entry" as="element()"/>
    <xsl:param name="bodyLayout" as="xs:string*"/>

    <xsl:for-each select="$entry">
      <!-- Remember that a table can contain another table. -->
      <xsl:variable name="tgroup" 
        select="(ancestor::*[contains(@class,' topic/tgroup ')])[last()]"/>
      <xsl:variable name="colspecs" 
                    select="$tgroup/*[contains(@class,' topic/colspec ')]"/>

      <xsl:choose>
        <xsl:when test="exists($colspecs)">
          <xsl:variable name="colname" select="@colname"/>
          <xsl:variable name="namest" select="@namest"/>

          <xsl:choose>
            <xsl:when test="exists($colname)">
              <xsl:sequence select="($colspecs[./@colname = $colname])[1]"/>
            </xsl:when>
            <xsl:when test="exists($namest)">
              <xsl:sequence select="($colspecs[./@colname = $namest][1])"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:choose>
                <xsl:when test="count($bodyLayout) gt 0">
                  <xsl:variable name="startColumn" 
                    select="u:entryStartColumn($entry, $bodyLayout)"/>
                  <xsl:sequence
                      select="for $colspec in $colspecs
                              return
                                if (u:colspecNumber($colspec) eq $startColumn)
                                then $colspec
                                else ()"/>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:sequence select="()"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>

        <xsl:otherwise>
          <xsl:sequence select="()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:function>

  <!-- localize ========================================================== -->

  <xsl:param name="messageFileNames"
             select="'en', 'fr', 'de', 'es', 'ru', 'cs'"/>

  <xsl:template name="localize">
    <xsl:param name="message" select="''"/>

    <xsl:variable name="lang">
      <xsl:call-template name="lang"/>
    </xsl:variable>

    <xsl:variable name="messageFileName">
      <xsl:choose>
        <xsl:when test="index-of($messageFileNames, $lang) ge 1">
          <xsl:value-of select="$lang"/>
        </xsl:when>
        <xsl:otherwise>en</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="messageFile"
                  select="concat('messages/', $messageFileName, '.xml')"/>

    <!-- Hope that documents loaded using document() are cached. -->
    <xsl:variable name="messages"
                  select="document($messageFile)/messages"/>

    <xsl:choose>
      <xsl:when test="$messages/message[@name=$message]">
        <xsl:value-of select="string($messages/message[@name=$message])"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$message"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="lang">
    <xsl:variable name="lang"
      select="lower-case(if (ancestor-or-self::*/@xml:lang) then 
                             string((ancestor-or-self::*/@xml:lang)[last()])
                         else 
                             'en')"/>
    
    <xsl:choose>
      <xsl:when test="contains($lang, '-')">
        <xsl:value-of select="substring-before($lang, '-')"/>
      </xsl:when>
      <xsl:when test="contains($lang, '_')">
        <xsl:value-of select="substring-before($lang, '_')"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$lang"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Function variant -->

  <xsl:function name="u:localize" as="xs:string">
    <xsl:param name="message" as="xs:string"/>
    <xsl:param name="context" as="element()"/>

    <xsl:for-each select="$context">
      <xsl:call-template name="localize">
        <xsl:with-param name="message" select="$message"/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:function>

</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<!--
| Copyright (c) 2009-2011 Pixware SARL. All rights reserved.
|
| Author: Hussein Shafie
|
| This file is part of the XMLmind DITA Converter project.
| For conditions of distribution and use, see the accompanying LEGAL.txt file.
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                xmlns:xs="http://www.w3.org/2001/XMLSchema";
                xmlns:u="http://www.xmlmind.com/namespace/ditac";
                xmlns:ditac="http://www.xmlmind.com/ditac/schema/ditac";
                xmlns:Number="java:com.xmlmind.ditac.xslt.Number"
                xmlns:URI="java:com.xmlmind.ditac.xslt.URI"
                exclude-result-prefixes="xs u ditac Number URI"
                version="2.0">

  <!-- ``System parameter'' automatically specified by the application hosting
       ditac. -->
  <xsl:param name="ditacListsURI" required="yes"/>
  <xsl:variable name="ditacLists" select="doc($ditacListsURI)/ditac:lists"/>

  <xsl:variable name="title-prefix-separator2" 
                select="u:localize('commaSeparator', $ditacLists)"/>

  <xsl:variable name="index-term-separator"
                select="u:localize('commaSeparator', $ditacLists)"/>
  <xsl:variable name="index-term-see-separator" 
                select="u:localize('periodSeparator', $ditacLists)"/>
  <xsl:variable name="index-hierarchical-term-separator" 
                select="u:localize('commaSeparator', $ditacLists)"/>
  <xsl:variable name="index-see-separator" 
                select="u:localize('semiColonSeparator', $ditacLists)"/>

  <!-- hasIndex ========================================================== -->

  <xsl:function name="u:hasIndex" as="xs:boolean">
    <xsl:sequence select="exists($ditacLists/ditac:indexList/*)"/>
  </xsl:function>

  <!-- currentChunk ====================================================== -->

  <xsl:function name="u:currentChunk" as="element()">
    <xsl:param name="docURI" as="xs:anyURI"/>

    <xsl:variable name="rootName" select="u:chunkRootName($docURI)"/>

    <xsl:sequence 
      select="$ditacLists/ditac:chunkList/ditac:chunk[u:matchRootName(@file, 
                                                                 $rootName)]"/>
  </xsl:function>

  <xsl:function name="u:chunkRootName" as="xs:string">
    <xsl:param name="docURI" as="xs:anyURI"/>

    <!-- $docURI is something like "file:/tmp/foo.ditac", 
         while chunk/@file is something like "foo.html". -->
    
    <xsl:variable name="baseName" select="u:basename($docURI)"/>

    <xsl:sequence select="substring-before($baseName, '.ditac')"/>
  </xsl:function>

  <xsl:function name="u:matchRootName" as="xs:boolean">
    <xsl:param name="baseName" as="xs:string"/>
    <xsl:param name="rootName" as="xs:string"/>

    <xsl:variable name="ext" select="u:extension($baseName)" />

    <xsl:sequence select="$baseName = concat($rootName, '.', $ext)" />
  </xsl:function>

  <!-- chunkIndex ======================================================== -->

  <xsl:function name="u:chunkIndex" as="xs:integer">
    <xsl:param name="docURI" as="xs:anyURI"/>

    <xsl:variable name="rootName" select="u:chunkRootName($docURI)"/>

    <xsl:for-each select="$ditacLists/ditac:chunkList/ditac:chunk">
      <xsl:choose>
        <xsl:when test="u:matchRootName(@file, $rootName)">
          <xsl:sequence select="position()"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:sequence select="()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:function>

  <!-- chunkCount ======================================================== -->

  <xsl:function name="u:chunkCount" as="xs:integer">
    <xsl:sequence select="count($ditacLists/ditac:chunkList/ditac:chunk)"/>
  </xsl:function>

  <!-- joinLinkTarget ==================================================== -->

  <xsl:function name="u:joinLinkTarget" as="xs:string">
    <xsl:param name="file" as="xs:string"/>
    <xsl:param name="id" as="xs:string"/>

    <xsl:sequence select="if (u:chunkCount() gt 1) then
                              concat($file, '#', $id)
                          else
                              concat('#', $id)"/>
  </xsl:function>

  <!-- chunk ============================================================= -->

  <xsl:function name="u:chunk" as="element()">
    <xsl:param name="index" as="xs:integer"/>

    <xsl:sequence select="$ditacLists/ditac:chunkList/ditac:chunk[$index]"/>
  </xsl:function>

  <!-- longChunkTitle ==================================================== -->

  <xsl:function name="u:longChunkTitle" as="xs:string">
    <xsl:param name="chunk" as="element()"/>

    <xsl:variable name="firstChild" select="$chunk/*[1]"/>
    <xsl:variable name="firstChildName" select="local-name($firstChild)"/>

    <xsl:variable name="title">
      <xsl:choose>
        <xsl:when test="$firstChildName = 'titlePage'">
          <xsl:value-of select="u:documentTitle()"/>
        </xsl:when>

        <xsl:when test="$firstChildName = 'topic'">
          <xsl:value-of select="string($firstChild/@title)"/>
        </xsl:when>

        <xsl:otherwise>
          <xsl:value-of
            select="u:localize(lower-case($firstChildName), $chunk)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="prefix">
      <xsl:choose>
        <xsl:when test="$firstChildName = 'topic'">
          <xsl:value-of
            select="u:longTitlePrefix(string($firstChild/@number), $chunk)"/>
        </xsl:when>

        <xsl:otherwise></xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$prefix != ''">
        <xsl:sequence 
          select="concat($prefix, $title-prefix-separator1, $title)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select="$title"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <!-- documentTitle ===================================================== -->

  <xsl:function name="u:documentTitle" as="xs:string">
    <xsl:variable name="title" 
     select="$ditacLists/ditac:titlePage/*[contains(@class,' topic/title ')]"/>

    <xsl:choose>
      <!-- When PreProcess option forceTitlePage is set to true, 
           ditac:titlePage/title may be empty. -->
      <xsl:when test="string($title) != ''">
        <!-- bookmap/booktitle is a specialization of topic/title. -->
        <xsl:variable name="bookTitle"
          select="$title//*[contains(@class,' bookmap/mainbooktitle ')]"/>

        <xsl:choose>
          <xsl:when test="exists($bookTitle)">
            <xsl:sequence select="normalize-space(string($bookTitle))"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:sequence select="normalize-space(string($title))"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <xsl:otherwise>
        <!-- Use the title of the first topic -->
        <xsl:sequence
            select="$ditacLists/ditac:chunkList/*/ditac:topic[1]/@title"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <!-- documentLang ====================================================== -->

  <xsl:function name="u:documentLang" as="xs:string">
    <xsl:variable name="lang" select="$ditacLists/@xml:lang"/>
    <xsl:sequence select="if (exists($lang)) then string($lang) else 'en'"/>
  </xsl:function>

  <!-- tocEntry=========================================================== -->

  <xsl:function name="u:tocEntry" as="element()?">
    <xsl:param name="id" as="xs:string"/>

      <!-- Topics contained in frontmatter/backmatter are not added to the
           ditac:toc. -->
    <xsl:sequence select="$ditacLists/ditac:toc//ditac:tocEntry[@id = $id]"/>
  </xsl:function>

  <!-- shortTOCEntryTitle ================================================ -->

  <xsl:function name="u:shortTOCEntryTitle" as="xs:string">
    <xsl:param name="tocEntry" as="element()"/>

    <xsl:variable name="title" select="string($tocEntry/@title)"/>

    <xsl:variable name="prefix" 
                  select="u:shortTitlePrefix(string($tocEntry/@number),
                                             $tocEntry)"/>

    <xsl:choose>
      <xsl:when test="$prefix != ''">
        <xsl:sequence
          select="concat($prefix, $title-prefix-separator1, $title)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select="$title"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <!-- shortTitlePrefix ================================================== -->

  <xsl:function name="u:shortTitlePrefix" as="xs:string">
    <xsl:param name="spec" as="xs:string"/>
    <xsl:param name="context" as="element()"/>
    
    <xsl:variable name="parts" select="u:splitSpec($spec)"/>
    <xsl:variable name="lastPart" select="$parts[last()]"/>

    <xsl:choose>
      <!-- format part|chapter|appendix -->
      <xsl:when test="(starts-with($lastPart, 'part.') and 
                       (index-of($numberList, 'all') ge 1 or 
                        index-of($numberList, 'topic') ge 1 or 
                        index-of($numberList, 'chapter-only') ge 1))
                      or
                      (starts-with($lastPart, 'chapter.') and 
                       (index-of($numberList, 'all') ge 1 or 
                        index-of($numberList, 'topic') ge 1 or 
                        index-of($numberList, 'chapter-only') ge 1))
                      or
                      (starts-with($lastPart, 'appendix.') and 
                       (index-of($numberList, 'all') ge 1 or 
                        index-of($numberList, 'topic') ge 1 or 
                        index-of($numberList, 'chapter-only') ge 1))">
        <xsl:variable name="label" 
                      select="u:localize(substring-before($lastPart, '.'), 
                                         $context)"/>

        <xsl:variable name="num"
                      select="u:formatNumbers($lastPart, $number-separator1)"/>

        <xsl:sequence select="concat($label, '&#xA0;', $num)"/>
      </xsl:when>

      <!-- Format everything after section1. 
           If option prepend-chapter-to-section-number, 
           prepend (chapter|appendix)? -->
      <xsl:when test="((starts-with($lastPart, 'section1.') or 
                        starts-with($lastPart, 'section2.') or 
                        starts-with($lastPart, 'section3.') or 
                        starts-with($lastPart, 'section4.') or 
                        starts-with($lastPart, 'section5.') or 
                        starts-with($lastPart, 'section6.') or 
                        starts-with($lastPart, 'section7.') or 
                        starts-with($lastPart, 'section8.') or 
                        starts-with($lastPart, 'section9.')) and 
                       (index-of($numberList, 'all') ge 1 or 
                        index-of($numberList, 'topic') ge 1))">
        <xsl:variable name="label" select="u:localize('section', $context)"/>

        <xsl:variable name="first"
                      select="for $part in $parts
                              return 
                                  if (starts-with($part, 'section1.')) then
                                      index-of($parts, $part)
                                  else
                                      ()"/>

        <xsl:choose>
          <xsl:when test="$first ge 1">
            <xsl:variable name="from"
              select="if ($prepend-chapter-to-section-number = 'yes' and
                          $first gt 1 and 
                          (starts-with($parts[$first - 1], 'chapter.') or 
                           starts-with($parts[$first - 1], 'appendix.'))) then
                          $first - 1
                      else
                          $first"/>

            <xsl:variable name="partRange" select="subsequence($parts,$from)"/>
            <xsl:variable name="num"
              select="u:formatNumbers($partRange, $number-separator1)"/>

            <xsl:sequence select="concat($label, '&#xA0;', $num)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:variable name="num"
              select="u:formatNumbers($lastPart, $number-separator1)"/>

            <xsl:sequence select="concat($label, '&#xA0;', $num)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <!-- Format (chapter|appendix)? table|figure|example.
           Note that 'all' includes 'table' and 'figure' but not 'example'.  -->
      <xsl:when test="(starts-with($lastPart, 'table.') and 
                       (index-of($numberList, 'all') ge 1 or 
                        index-of($numberList, 'table') ge 1))
                      or
                      (starts-with($lastPart, 'figure.') and 
                       (index-of($numberList, 'all') ge 1 or 
                        index-of($numberList, 'fig') ge 1))
                      or
                      (starts-with($lastPart, 'example.') and 
                       index-of($numberList, 'example') ge 1)">
        <xsl:variable name="label" 
                      select="u:localize(substring-before($lastPart, '.'), 
                                         $context)"/>

        <xsl:variable name="partRange" 
                      select="if (starts-with($parts[1], 'part.')) then 
                                  remove($parts, 1) 
                              else 
                                  $parts"/>
        <xsl:variable name="num"
          select="u:formatNumbers($partRange, $number-separator2)"/>

        <xsl:sequence select="concat($label, '&#xA0;', $num)"/>
      </xsl:when>

      <!-- Examples: preface, glossary, etc, which are never numbered. -->
      <xsl:otherwise>
        <xsl:sequence select="''"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="u:splitSpec" as="xs:string*">
    <xsl:param name="spec" as="xs:string"/>

    <xsl:variable name="parts" select="tokenize($spec, '\s+')"/>

    <!-- There is at most a single appendices element per bookmap.  
         Therefore it does not make sense to number it. -->

    <xsl:sequence select="if ($parts[1] = 'appendices.1') 
                          then subsequence($parts, 2)
                          else $parts" />
  </xsl:function>

  <xsl:function name="u:formatNumbers" as="xs:string">
    <xsl:param name="parts" as="xs:string*"/>
    <xsl:param name="separator" as="xs:string"/>

    <!-- There is at most a single 'appendices'. It's not numbered.
         ('appendices.1' has already been filtered out from the tocEntry
         number.) -->

    <xsl:variable name="numList" 
      select="for $part in $parts
              return
                  if (substring-before($part, '.') = 'part') then
                      Number:format(number(substring-after($part, '.')),
                                    $part-number-format)
                  else
                      if (substring-before($part, '.') = 'appendix') then
                          Number:format(number(substring-after($part, '.')),
                                        $appendix-number-format)
                      else
                          substring-after($part, '.')"/>

    <xsl:sequence select="string-join($numList, $separator)"/>
  </xsl:function>

  <!-- longTitlePrefix =================================================== -->

  <xsl:function name="u:longTitlePrefix" as="xs:string">
    <xsl:param name="spec" as="xs:string"/>
    <xsl:param name="context" as="element()"/>

    <xsl:sequence select="string-join(u:titlePrefixSegments($spec, $context), 
                                      $title-prefix-separator2)"/>
  </xsl:function>

  <xsl:function name="u:titlePrefixSegments" as="xs:string*">
    <xsl:param name="spec" as="xs:string"/>
    <xsl:param name="context" as="element()"/>
    
    <xsl:variable name="prefix" select="u:shortTitlePrefix($spec, $context)"/>

    <xsl:choose>
      <xsl:when test="$prefix != ''">
        <xsl:variable name="parts" select="u:splitSpec($spec)"/>
        <xsl:variable name="lastPart" select="$parts[last()]"/>

        <xsl:choose>
          <xsl:when test="starts-with($lastPart, 'section1.') or
                          starts-with($lastPart, 'section2.') or
                          starts-with($lastPart, 'section3.') or
                          starts-with($lastPart, 'section4.') or
                          starts-with($lastPart, 'section5.') or
                          starts-with($lastPart, 'section6.') or
                          starts-with($lastPart, 'section7.') or
                          starts-with($lastPart, 'section8.') or
                          starts-with($lastPart, 'section9.')
                          or
                          starts-with($lastPart, 'figure.') or
                          starts-with($lastPart, 'table.') or
                          starts-with($lastPart, 'example.')">
            <!-- Prepend "Part N, Chapter M" or "Appendix L", if any. -->

            <!-- Notes:
                 * Prepending "Part N, Chapter M" or "Appendix L" to
                   a figure, table or example may be a bit redundant 
                   but at least, it's crystal clear. -->

            <xsl:variable name="end"
                          select="for $part in $parts
                                  return 
                                      if (starts-with($part, 'section1.') or
                                          starts-with($part, 'figure.') or
                                          starts-with($part, 'table.') or
                                          starts-with($part, 'example.')) then
                                          index-of($parts, $part)
                                      else
                                          ()"/>
            <xsl:choose>
              <xsl:when test="$end gt 1">
                <xsl:variable name="partRange" 
                              select="subsequence($parts, 1, $end - 1)"/>

                <xsl:sequence 
                  select="(u:formatSegments($partRange, $context), $prefix)"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:sequence select="$prefix"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>

          <xsl:when test="starts-with($lastPart, 'chapter.') or
                          starts-with($lastPart, 'appendix.')">
            <!-- Prepend "Part N", if any -->
            <xsl:variable name="firstPart" 
                          select="if (starts-with($parts[1], 'part.')) then 
                                      $parts[1]
                                  else 
                                      ()"/>

            <xsl:choose>
              <xsl:when test="exists($firstPart)">
                <xsl:sequence 
                  select="(u:formatSegments($firstPart, $context), $prefix)"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:sequence select="$prefix"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>

          <xsl:otherwise>
            <xsl:sequence select="$prefix"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <xsl:otherwise>
        <xsl:sequence select="()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="u:formatSegments" as="xs:string*">
    <xsl:param name="parts" as="xs:string*"/>
    <xsl:param name="context" as="element()"/>

    <xsl:sequence 
      select="for $part in $parts
              return
                  concat(u:localize(substring-before($part, '.'), $context), 
                         '&#xA0;', 
                         u:formatNumbers($part, $number-separator1))"/>
  </xsl:function>

  <!-- runningChapterTitle =============================================== -->

  <xsl:function name="u:runningChapterTitle" as="xs:string">
    <xsl:param name="id" as="xs:string"/>

    <xsl:variable name="tocEntry" select="u:tocEntry($id)"/>
    <xsl:choose>
      <xsl:when test="exists($tocEntry)">
        <xsl:variable name="role" select="string($tocEntry/@role)"/>
        <xsl:choose>
          <xsl:when test="$role = 'part' or
                          $role = 'chapter' or
                          $role = 'appendices' or
                          $role = 'appendix'">
            <xsl:variable name="prefix" 
              select="u:shortTitlePrefix(string($tocEntry/@number),
                                         $tocEntry)"/>
            <xsl:choose>
              <xsl:when test="$prefix != ''">
                <xsl:sequence select="concat($prefix, $title-prefix-separator1,
                                             $tocEntry/@title)"/>
              </xsl:when>
              <xsl:otherwise>
                <!-- Not numbered -->
                <xsl:sequence select="string($tocEntry/@title)"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>

          <xsl:when test="$role = 'section1'">
            <xsl:variable name="prefix" 
              select="u:shortTitlePrefix(string($tocEntry/@number),
                                         $tocEntry)"/>
            <xsl:choose>
              <xsl:when test="$prefix != ''">
                <!-- Do not keep the leading 'Section' -->
                <xsl:value-of 
                  select="concat(substring-after($prefix, '&#xA0;'),
                                 $title-prefix-separator1,
                                 $tocEntry/@title)"/>
              </xsl:when>
              <xsl:otherwise>
                <!-- Not numbered -->
                <xsl:sequence select="string($tocEntry/@title)"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>

          <xsl:otherwise>
            <!-- Not a part, chapter, appendix or section1. -->
            <xsl:sequence select="''"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <xsl:otherwise>
        <!-- Should not happen -->
        <xsl:sequence select="''"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <!-- topicTitleClass =================================================== -->

  <xsl:template name="topicTitleClass">
    <xsl:variable name="topicId" select="../@id"/>
    <xsl:variable name="tocEntry" select="u:tocEntry($topicId)"/>

    <xsl:choose>
      <xsl:when test="exists($tocEntry)">
        <xsl:variable name="role" select="string($tocEntry/@role)"/>
        <xsl:choose>
          <xsl:when test="$role = 'part' or
                          $role = 'chapter' or
                          $role = 'appendices' or
                          $role = 'appendix' or
                          $role = 'section1' or
                          $role = 'section2' or
                          $role = 'section3' or
                          $role = 'section4' or
                          $role = 'section5' or
                          $role = 'section6' or
                          $role = 'section7' or
                          $role = 'section8' or
                          $role = 'section9'">
            <xsl:value-of select="concat($role, '-title')"/>
          </xsl:when>
          <xsl:otherwise>topic-title</xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>topic-title</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- titlePrefix ======================================================= -->

  <xsl:template name="titlePrefix">
    <xsl:variable name="parent" select="parent::*"/>
    <xsl:variable name="id" select="string($parent/@id)"/>

    <xsl:if test="$id != ''">
      <xsl:choose>
        <xsl:when test="contains($parent/@class,' topic/topic ')">
          <xsl:variable name="tocEntry" select="u:tocEntry($id)"/>
          <xsl:if test="exists($tocEntry)">
            <xsl:variable name="prefix" 
                          select="u:shortTitlePrefix(string($tocEntry/@number),
                                                     $tocEntry)"/>
            <xsl:if test="$prefix != ''">
              <xsl:variable name="role" select="string($tocEntry/@role)"/>
              <xsl:choose>
                <xsl:when test="$role = 'section1' or
                                $role = 'section2' or
                                $role = 'section3' or
                                $role = 'section4' or
                                $role = 'section5' or
                                $role = 'section6' or
                                $role = 'section7' or
                                $role = 'section8' or
                                $role = 'section9'">
                  <!-- Do not keep the leading 'Section' -->
                  <xsl:value-of 
                    select="concat(substring-after($prefix, '&#xA0;'),
                                   $title-prefix-separator1)"/>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="concat($prefix,
                                               $title-prefix-separator1)"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:if>
            <!-- Otherwise, chapters, sections, etc, are not numbered. -->
          </xsl:if>
          <!-- Topics contained in front/backmatter are not added to toc. -->
        </xsl:when>

        <xsl:when test="contains($parent/@class,' topic/fig ')">
          <xsl:variable name="figure" 
            select="$ditacLists/ditac:figureList/ditac:figure[@id = $id]"/>
          <xsl:if test="exists($figure)">
            <xsl:variable name="prefix" 
                          select="u:shortTitlePrefix(string($figure/@number), 
                                                     $figure)"/>
            <xsl:if test="$prefix != ''">
              <xsl:value-of select="concat($prefix,
                                           $title-prefix-separator1)"/>
            </xsl:if>
            <!-- Otherwise, figure are not numbered. -->
          </xsl:if>
          <!-- Figures having no title are not added to figureList. -->
        </xsl:when>

        <xsl:when test="contains($parent/@class,' topic/table ')">
          <xsl:variable name="table" 
            select="$ditacLists/ditac:tableList/ditac:table[@id = $id]"/>
          <xsl:if test="exists($table)">
            <xsl:variable name="prefix" 
                          select="u:shortTitlePrefix(string($table/@number),
                                                     $table)"/>
            <xsl:if test="$prefix != ''">
              <xsl:value-of select="concat($prefix,
                                           $title-prefix-separator1)"/>
            </xsl:if>
            <!-- Otherwise, tables are not numbered. -->
          </xsl:if>
          <!-- Tables having no title are not added to tableList. -->
        </xsl:when>

        <xsl:when test="contains($parent/@class,' topic/example ')">
          <xsl:variable name="example" 
            select="$ditacLists/ditac:exampleList/ditac:example[@id = $id]"/>
          <xsl:if test="exists($example)">
            <xsl:variable name="prefix" 
                          select="u:shortTitlePrefix(string($example/@number), 
                                                     $example)"/>

            <xsl:if test="$prefix != ''">
              <xsl:value-of select="concat($prefix,
                                    $title-prefix-separator1)"/>
            </xsl:if>
            <!-- Otherwise, examples are not numbered. -->
          </xsl:if>
          <!-- Examples having no title are not added to exampleList. -->
        </xsl:when>
      </xsl:choose>
    </xsl:if>
  </xsl:template>

  <!-- linkPrefix ======================================================== -->

  <xsl:template name="linkPrefix">
    <xsl:variable name="id" select="u:linkTargetId(string(@href))"/>

    <!-- The preprocessor never generates nested topics. -->
    <xsl:variable name="topicId" 
                  select="ancestor::*[contains(@class,' topic/topic ')]/@id"/>
    <xsl:variable name="topicEntry" select="u:tocEntry($topicId)"/>
    <xsl:variable name="topicNumber" 
                  select="if (exists($topicEntry)) then 
                              string($topicEntry/@number) 
                          else 
                              ''"/>

    <xsl:if test="$id != ''">
      <xsl:variable name="tocEntry" select="u:tocEntry($id)"/>
      <xsl:choose>
        <xsl:when test="exists($tocEntry)">
          <xsl:variable name="prefix" 
            select="u:relativeTitlePrefix(string($tocEntry/@number),
                                          $topicNumber,
                                          $tocEntry)"/>
          <xsl:if test="$prefix != ''">
            <xsl:value-of select="concat($prefix,
                                         $title-prefix-separator1)"/>
          </xsl:if>
        </xsl:when>

        <xsl:otherwise>
          <xsl:variable name="figure" 
            select="$ditacLists/ditac:figureList/ditac:figure[@id = $id]"/>
          <xsl:choose>
            <xsl:when test="exists($figure)">
              <xsl:variable name="prefix" 
                select="u:relativeTitlePrefix(string($figure/@number),
                                              $topicNumber,
                                              $figure)"/>
              <xsl:if test="$prefix != ''">
                <xsl:value-of select="concat($prefix,
                                             $title-prefix-separator1)"/>
              </xsl:if>
            </xsl:when>

            <xsl:otherwise>
              <xsl:variable name="table" 
                select="$ditacLists/ditac:tableList/ditac:table[@id = $id]"/>
              <xsl:choose>
                <xsl:when test="exists($table)">
                  <xsl:variable name="prefix" 
                    select="u:relativeTitlePrefix(string($table/@number),
                                                  $topicNumber,
                                                  $table)"/>
                  <xsl:if test="$prefix != ''">
                    <xsl:value-of select="concat($prefix,
                                                 $title-prefix-separator1)"/>
                  </xsl:if>
                </xsl:when>

                <xsl:otherwise>
                  <xsl:variable name="example" 
                    select="$ditacLists/ditac:exampleList/ditac:example[@id = $id]"/>
                  <xsl:if test="exists($example)">
                    <xsl:variable name="prefix" 
                      select="u:relativeTitlePrefix(string($example/@number),
                                                    $topicNumber,
                                                    $example)"/>
                    <xsl:if test="$prefix != ''">
                      <xsl:value-of select="concat($prefix,
                                                   $title-prefix-separator1)"/>
                    </xsl:if>
                  </xsl:if>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
  </xsl:template>

  <xsl:function name="u:linkTargetId">
    <xsl:param name="href" as="xs:string"/>

    <!-- The preprocessor always appends #flat_id to local links. -->
    <xsl:sequence select="if (contains($href, '#') and 
                              not(contains($href, '/'))) then
                              URI:decodeURI(substring-after($href, '#'))
                          else
                              ''"/>
  </xsl:function>

  <xsl:function name="u:relativeTitlePrefix" as="xs:string">
    <xsl:param name="spec" as="xs:string"/>
    <xsl:param name="baseSpec" as="xs:string"/>
    <xsl:param name="context" as="element()"/>
    
    <xsl:choose>
      <xsl:when test="$baseSpec != ''">
        <xsl:variable name="prefix" 
                      select="u:shortTitlePrefix($spec, $context)"/>

        <xsl:choose>
          <xsl:when test="$prefix != ''">
            <xsl:variable name="parts1" select="u:splitSpec($spec)"/>
            <xsl:variable name="parts2" select="u:splitSpec($baseSpec)"/>

            <xsl:variable name="commonList" 
              select="for $p1 in $parts1, $p2 in $parts2
                      return
                          if ($p1 = $p2 and
                              (starts-with($p1, 'part.') or
                               starts-with($p1, 'chapter.') or 
                               starts-with($p1, 'appendix.'))) then
                              $p1
                          else
                              ()"/>
            <xsl:variable name="common" select="$commonList[last()]"/>

            <xsl:choose>
              <xsl:when test="starts-with($common, 'chapter.') or 
                              starts-with($common, 'appendix.')">
                <!-- It is OK if spec and baseSpec are the same chapter or
                     appendix. -->
                <xsl:sequence select="$prefix"/>
              </xsl:when>

              <xsl:when test="starts-with($common, 'part.')">
                <!-- Discard leading 'Part NNN, ' -->

                <xsl:choose>
                  <xsl:when test="count($parts1) eq 1">
                    <!-- Spec specifies a part. Nothing to discard. -->
                    <xsl:sequence select="$prefix"/>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:variable name="longPrefix"
                                  select="u:longTitlePrefix($spec, $context)"/>
                    <xsl:sequence 
                        select="substring-after($longPrefix, 
                                                $title-prefix-separator2)"/>
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:when>

              <xsl:otherwise>
                <!-- Fallback. Also happens when spec and/or baseSpec have
                     no part/chapter/appendix at all. -->
                <xsl:sequence select="u:longTitlePrefix($spec, $context)"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:when>

          <xsl:otherwise>
            <xsl:sequence select="''"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <xsl:otherwise>
        <xsl:sequence select="u:longTitlePrefix($spec, $context)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <!-- canFlag =========================================================== -->

  <!-- ===================================================================
       About flaggableBlockElements: these elements are the children of body.
       Notes:
       * parml specializes dl 
       * codeblock, msgblock, screen specialize pre
       * syntaxdiagram, imagemap specialize fig
       * image, foreign, data, data-about, etc, are considered to be inline

       About flaggableInlineElements: these elements are the children of ph.
       Notes:
       * Most omitted elements specialize ph or keyword.
       * Elements such as indexterm, data, unknown, etc, are not rendered.
       * Element fn is neither an inline or a block.
       =================================================================== -->

  <xsl:variable name="flaggableBlockElements" 
                select="'topic/topic', 
                        'topic/p', 
                        'topic/lq', 
                        'topic/note', 
                        'topic/dl', 
                        'topic/ul', 
                        'topic/ol', 
                        'topic/sl', 
                        'topic/pre', 
                        'topic/lines', 
                        'topic/fig', 
                        'topic/object', 
                        'topic/table', 
                        'topic/simpletable', 
                        'topic/section', 
                        'topic/example'"/>
  <xsl:variable name="flaggableInlineElements" 
                select="'topic/ph',
                        'topic/term', 
                        'topic/xref', 
                        'topic/cite', 
                        'topic/q', 
                        'topic/boolean', 
                        'topic/state', 
                        'topic/keyword', 
                        'topic/tm', 
                        'topic/image', 
                        'topic/foreign'"/>

  <xsl:function name="u:canFlag" as="xs:integer">
    <xsl:param name="subject" as="element()"/>

    <xsl:variable name="class" select="tokenize($subject/@class, '\s+')"/>
    <xsl:choose>
      <xsl:when test="u:intersects($flaggableBlockElements, $class)">
        <xsl:sequence select="1"/>
      </xsl:when>
      <xsl:when test="u:intersects($flaggableInlineElements, $class)">
        <xsl:sequence select="2"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select="0"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

  <xsl:function name="u:intersects" as="xs:boolean">
    <xsl:param name="list1" as="xs:string*"/>
    <xsl:param name="list2" as="xs:string*"/>

    <xsl:variable name="result" select="for $item2 in $list2 
                                        return index-of($list1, $item2)"/>
    <xsl:choose>
      <xsl:when test="empty($result)">
        <xsl:sequence select="false()"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select="true()"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:function>

</xsl:stylesheet>

 
--
XMLmind DITA Converter Support List
[email protected]
http://www.xmlmind.com/mailman/listinfo/ditac-support

Reply via email to