<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:c="http://daisymfc.sf.net/xslt/config" xmlns:pfunc="http://daisymfc.sf.net/xslt/function" xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2.0" exclude-result-prefixes="html c xs pfunc"> <c:config> <c:generator>DMFC Daisy 2.02 to z3986-2005</c:generator> <c:name>d202ncc_Z2005ncx</c:name> <c:version>0.1</c:version> <c:author>Brandon Nelson</c:author> <c:description>Creates the Z2005 ncx file.</c:description> </c:config> <xsl:param name="uid" as="xs:string"/> <xsl:param name="smils" as="document-node(element(smil))*"/> <xsl:param name="smilCustomTests" as="xs:string*" select="()"/> <xsl:param name="defaultStatePagenumbers" as="xs:string" select="'true'"/> <xsl:param name="defaultStateSidebars" as="xs:string" select="'true'"/> <xsl:param name="defaultStateFootnotes" as="xs:string" select="'true'"/> <xsl:param name="defaultStateProdnotes" as="xs:string" select="'true'"/> <xsl:param name="addNavLabelAudio" as="xs:string" select="'false'"/> <xsl:param name="minNavLabelAudioLength" as="xs:integer" select="1000"/> <xsl:template match="/html:html"> <ncx version="2005-1"> <xsl:attribute name="xml:lang"> <xsl:choose> <xsl:when test="@xml:lang"> <xsl:value-of select="@xml:lang"/> </xsl:when> <xsl:when test="//html:meta[@name eq 'dc:language']"> <xsl:value-of select="//html:meta[@name eq 'dc:language'][1]/@content"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="'en'"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:apply-templates select="html:head"/> <xsl:apply-templates select="html:body"/> </ncx> </xsl:template> <xsl:template match="html:head"> <head> <meta name="dtb:uid" content="{$uid}"/> <meta name="dtb:depth" content="{html:meta[@name='ncc:depth']/@content}"/> <meta name="dtb:generator" content="Pipeline Daisy 2.02 to z39.86-2005"/> <meta name="dtb:totalPageCount" content="{html:meta[@name='ncc:pageFront']/@content + html:meta[@name='ncc:pageNormal']/@content + html:meta[@name='ncc:pageSpecial']/@content}"/> <xsl:choose> <xsl:when test="//html:span[@class='page-normal']"> <meta name="dtb:maxPageNumber" content="{max(//html:span[@class='page-normal'])}"/> </xsl:when> <xsl:otherwise> <meta name="dtb:maxPageNumber" content="0"/> </xsl:otherwise> </xsl:choose> <xsl:for-each select="$smilCustomTests"> <smilCustomTest id="{.}" override="visible"> <xsl:attribute name="defaultState"> <xsl:choose> <xsl:when test=". eq 'pagenumber'"><xsl:value-of select="$defaultStatePagenumbers"/></xsl:when> <xsl:when test=". eq 'sidebar'"><xsl:value-of select="$defaultStateSidebars"/></xsl:when> <xsl:when test=". eq 'footnote'"><xsl:value-of select="$defaultStateFootnotes"/></xsl:when> <xsl:when test=". eq 'prodnote'"><xsl:value-of select="$defaultStateProdnotes"/></xsl:when> <xsl:otherwise><xsl:value-of select="'true'"/></xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:attribute name="bookStruct"> <xsl:choose> <xsl:when test=". eq 'pagenumber'">PAGE_NUMBER</xsl:when> <xsl:when test=". eq 'sidebar'">OPTIONAL_SIDEBAR</xsl:when> <xsl:when test=". eq 'footnote'">NOTE</xsl:when> <xsl:when test=". eq 'prodnote'">OPTIONAL_PRODUCER_NOTE</xsl:when> <xsl:otherwise>UNKNOWN_BOOKSTRUCT</xsl:otherwise> </xsl:choose> </xsl:attribute> </smilCustomTest> </xsl:for-each> <xsl:for-each select="html:meta[not(@http-equiv or starts-with(@name,'dtb:'))]"> <meta> <xsl:copy-of select="@*"/> </meta> </xsl:for-each> </head> <docTitle> <text><xsl:value-of select="html:title"/></text> </docTitle> <xsl:apply-templates select="html:meta[@name='dc:creator']"/> </xsl:template> <xsl:template match="html:meta[@name='dc:creator']"> <docAuthor> <text><xsl:value-of select="@content"/></text> </docAuthor> </xsl:template> <xsl:template match="html:body"> <xsl:call-template name="navMap"/> <xsl:if test="html:span[@class='page-normal' or @class='page-front' or @class='page-special']"> <xsl:call-template name="pageList"/> </xsl:if> <xsl:if test="html:div[@class eq 'group']"> <xsl:call-template name="navListDiv"/> </xsl:if> <xsl:if test="html:span[matches(@class,'^sidebar$|^optional-prodnote$|^noteref$')]"> <xsl:call-template name="navListSpan"/> </xsl:if> </xsl:template> <xsl:template name="navMap"> <navMap> <xsl:apply-templates select="html:h1"/> </navMap> </xsl:template> <xsl:template match="html:h1|html:h2|html:h3|html:h4|html:h5|html:h6"> <navPoint id="{@id}" class="{local-name()}"><xsl:attribute name="playOrder"><xsl:call-template name="positionInNCC"/></xsl:attribute> <navLabel> <text><xsl:value-of select="normalize-space(.)"/></text> <xsl:if test="matches($addNavLabelAudio,'true','i')"> <xsl:call-template name="navLabelAudio"/> </xsl:if> </navLabel> <content src="{html:a/@href}"/> <xsl:apply-templates select="key('nextHeadings', generate-id(.))"/> </navPoint> </xsl:template> <xsl:template name="pageList"> <pageList> <xsl:apply-templates select="html:span[@class='page-normal' or @class='page-front' or @class='page-special']"/> </pageList> </xsl:template> <xsl:template match="html:span[@class='page-normal' or @class='page-front' or @class='page-special']"> <pageTarget class="pagenum" type="{substring-after(@class, '-')}" value="{normalize-space(.)}" id="{@id}"> <xsl:attribute name="playOrder"><xsl:call-template name="positionInNCC"/></xsl:attribute> <navLabel> <text><xsl:value-of select="normalize-space(.)"/></text> <xsl:if test="matches($addNavLabelAudio,'true','i')"> <xsl:call-template name="navLabelAudio"/> </xsl:if> </navLabel> <content src="{html:a/@href}"/> </pageTarget> </xsl:template> <xsl:template name="navListDiv"> <navList id="navlist-group" class="group"> <navInfo> <text>This list contains the <xsl:value-of select="count(html:div[@class eq 'group'])"/> groups found in this book.</text> </navInfo> <navLabel> <text>Groups</text> </navLabel> <xsl:apply-templates select="html:div[@class eq 'group']"/> </navList> </xsl:template> <xsl:template name="navListSpan"> <xsl:variable name="dtbBody" as="element()" select="//html:body"/> <xsl:variable name="spanType" as="xs:string*" select="distinct-values(for $e in html:span[matches(@class,'^sidebar$|^optional-prodnote$|^noteref$')] return $e/@class)"/> <xsl:for-each select="$spanType"> <xsl:variable name="type" as="xs:string" select="."/> <navList id="navlist-{$type}" class="{$type}"> <navInfo> <text>The list contains the <xsl:value-of select="count($dtbBody/html:span[@class eq $type])"/> <xsl:text> </xsl:text> <xsl:choose> <xsl:when test="$type eq 'sidebar'">sidebars</xsl:when> <xsl:when test="$type eq 'optional-prodnote'">optional producer notes</xsl:when> <xsl:otherwise>notes</xsl:otherwise> </xsl:choose> found in this book.</text> </navInfo> <navLabel> <text> <xsl:choose> <xsl:when test="$type eq 'sidebar'">Sidebars</xsl:when> <xsl:when test="$type eq 'optional-prodnote'">Optional producer notes</xsl:when> <xsl:otherwise>Notes</xsl:otherwise> </xsl:choose> </text> </navLabel> <xsl:apply-templates select="$dtbBody/html:span[@class eq $type]"/> </navList> </xsl:for-each> </xsl:template> <xsl:template match="html:span[matches(@class,'^sidebar$|^optional-prodnote$|^noteref$')] | html:div[@class eq 'group']"> <navTarget class="{@class}" id="{concat(@class,'-',position())}"> <xsl:attribute name="playOrder"><xsl:call-template name="positionInNCC"/></xsl:attribute> <navLabel> <text><xsl:value-of select="normalize-space(.)"/></text> <xsl:if test="matches($addNavLabelAudio,'true','i')"> <xsl:call-template name="navLabelAudio"/> </xsl:if> </navLabel> <content src="{html:a/@href}"/> </navTarget> </xsl:template> <xsl:template name="navLabelAudio"> <xsl:variable name="SMIL.filename" as="xs:anyURI" select="html:a/resolve-uri(substring-before(@href,'#'),base-uri(.))"/> <xsl:variable name="SMIL.id" as="xs:string" select="substring-after(html:a/@href,'#')"/> <xsl:variable name="SMIL" select="$smils[base-uri(/*)=$SMIL.filename]/id($SMIL.id)"/> <xsl:variable name="audioElements" as="element()*"> <xsl:choose> <xsl:when test="local-name($SMIL) eq 'text'"> <xsl:for-each select="$SMIL"> <xsl:for-each select="following-sibling::seq/audio"> <xsl:sequence select="."/> </xsl:for-each> </xsl:for-each> </xsl:when> <xsl:when test="local-name($SMIL) eq 'par'"> <xsl:for-each select="$SMIL"> <xsl:for-each select="seq/audio"> <xsl:sequence select="."/> </xsl:for-each> </xsl:for-each> </xsl:when> <xsl:otherwise/> </xsl:choose> </xsl:variable> <xsl:if test="$audioElements"> <xsl:variable name="numberOfAudioElementsToUse" as="xs:integer" select=" if ( pfunc:audioEventDuration($audioElements[1]) lt $minNavLabelAudioLength (: if first audioevent is too short :) and count($audioElements) gt 1 (: and there is another one :) ) then 2 (: use both of them :) else 1 (: if not; use the first one only :) "/> <xsl:choose> <xsl:when test="($numberOfAudioElementsToUse gt 1) and (count(distinct-values($audioElements[position() le $numberOfAudioElementsToUse]/@src)) eq 1)"> <audio src="{$audioElements[1]/@src}" clipBegin="{pfunc:createZedClipValue($audioElements[1]/@clip-begin)}" clipEnd="{pfunc:createZedClipValue($audioElements[$numberOfAudioElementsToUse]/@clip-end)}"/> </xsl:when> <xsl:otherwise> <audio src="{$audioElements[1]/@src}" clipBegin="{pfunc:createZedClipValue($audioElements[1]/@clip-begin)}" clipEnd="{pfunc:createZedClipValue($audioElements[1]/@clip-end)}"/> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:template> <xsl:function name="pfunc:audioEventDuration" as="xs:integer"> <xsl:param name="audioElement" as="element()"/> <xsl:variable name="clipBegin" as="xs:integer" select="pfunc:d202ClipValue2Ms($audioElement/@clip-begin)"/> <xsl:variable name="clipEnd" as="xs:integer" select="pfunc:d202ClipValue2Ms($audioElement/@clip-end)"/> <xsl:value-of select=" if ($clipEnd gt $clipBegin) then $clipEnd - $clipBegin else 0 "/> </xsl:function> <xsl:function name="pfunc:d202ClipValue2Ms" as="xs:integer"> <xsl:param name="clipValue" as="xs:string"/> <xsl:analyze-string select="$clipValue" regex="^npt=([0-9]*\.?[0-9]*)((h|min|s|ms)?)$"> <xsl:matching-substring> <xsl:choose> <xsl:when test="regex-group(2) eq 'h'"> <xsl:value-of select="xs:integer(round(number(regex-group(1)) * 3600 * 1000))"/> </xsl:when> <xsl:when test="regex-group(2) eq 'min'"> <xsl:value-of select="xs:integer(round(number(regex-group(1)) * 60 * 1000))"/> </xsl:when> <xsl:when test="regex-group(2) eq 'ms'"> <xsl:value-of select="xs:integer(round(number(regex-group(1))))"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="xs:integer(round(number(regex-group(1)) * 1000))"/> </xsl:otherwise> </xsl:choose> </xsl:matching-substring> <xsl:non-matching-substring> <xsl:value-of select="0"/> </xsl:non-matching-substring> </xsl:analyze-string> </xsl:function> <xsl:function name="pfunc:createZedClipValue" as="xs:string"> <xsl:param name="daisy202ClipValue" as="xs:string"/> <xsl:value-of select="$daisy202ClipValue"/> </xsl:function> <xsl:template name="positionInNCC"> <xsl:value-of select="count(preceding::*[ self::html:span[matches(@class,'^sidebar$|^optional-prodnote$|^noteref$')] or self::html:div[@class eq 'group'] or self::html:h1 or self::html:h2 or self::html:h3 or self::html:h4 or self::html:h5 or self::html:h6 or self::html:span[substring-before(@class, '-')='page']]) + 1"/> </xsl:template> <xsl:key name="nextHeadings" match="html:h6" use="generate-id(preceding-sibling::*[self::html:h1 or self::html:h2 or self::html:h3 or self::html:h4 or self::html:h5][1])"/> <xsl:key name="nextHeadings" match="html:h5" use="generate-id(preceding-sibling::*[self::html:h1 or self::html:h2 or self::html:h3 or self::html:h4][1])"/> <xsl:key name="nextHeadings" match="html:h4" use="generate-id(preceding-sibling::*[self::html:h1 or self::html:h2 or self::html:h3][1])"/> <xsl:key name="nextHeadings" match="html:h3" use="generate-id(preceding-sibling::*[self::html:h1 or self::html:h2][1])"/> <xsl:key name="nextHeadings" match="html:h2" use="generate-id(preceding-sibling::html:h1[1])"/> </xsl:stylesheet>