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> </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, ' ', $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, ' ', $num)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="num"
select="u:formatNumbers($lastPart, $number-separator1)"/>
<xsl:sequence select="concat($label, ' ', $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, ' ', $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),
' ',
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, ' '),
$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, ' '),
$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