<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:css="http://www.daisy.org/ns/pipeline/braille-css" xmlns:pxi="http://www.daisy.org/ns/pipeline/xproc/internal" xmlns:re="regex-utils" exclude-result-prefixes="#all" version="2.0">
<xsl:variable name="css:SYMBOL_RE" select="re:or(($css:IDENT_RE,$css:STRING_RE))"/>
<xsl:variable name="css:SYMBOL_RE_ident" select="1"/>
<xsl:variable name="css:SYMBOL_RE_string" select="$css:SYMBOL_RE_ident + $css:IDENT_RE_groups + 1"/>
<xsl:variable name="css:SYMBOL_RE_groups" select="$css:SYMBOL_RE_string + $css:STRING_RE_groups"/>
<xsl:variable name="css:SYMBOLS_FN_RE" select="concat('symbols\(\s*((',$css:IDENT_RE,')\s+)?((',$css:STRING_RE,')(\s+(',$css:STRING_RE,'))*)\s*\)')"/>
<xsl:variable name="css:SYMBOLS_FN_RE_type" select="2"/>
<xsl:variable name="css:SYMBOLS_FN_RE_symbols" select="$css:SYMBOLS_FN_RE_type + $css:IDENT_RE_groups + 1"/>
<xsl:variable name="css:SYMBOLS_FN_RE_groups" select="$css:SYMBOLS_FN_RE_symbols + 1 + $css:STRING_RE_groups + 2 + $css:STRING_RE_groups"/>
<xsl:variable name="css:COUNTER_STYLE_RE" select="concat('(',$css:IDENT_RE,')|(',$css:SYMBOLS_FN_RE,')')"/>
<xsl:variable name="css:COUNTER_STYLE_RE_name" select="1"/>
<xsl:variable name="css:COUNTER_STYLE_RE_symbols_type" select="$css:COUNTER_STYLE_RE_name + $css:IDENT_RE_groups + 1 + $css:SYMBOLS_FN_RE_type"/>
<xsl:variable name="css:COUNTER_STYLE_RE_symbols" select="$css:COUNTER_STYLE_RE_name + $css:IDENT_RE_groups + 1 + $css:SYMBOLS_FN_RE_symbols"/>
<xsl:variable name="css:COUNTER_STYLE_RE_groups" select="$css:COUNTER_STYLE_RE_name + $css:IDENT_RE_groups + 1 + $css:SYMBOLS_FN_RE_groups"/>
<xsl:function name="css:parse-symbols" as="xs:string*">
<xsl:param name="symbols" as="xs:string"/>
<xsl:analyze-string select="$symbols" regex="{$css:SYMBOL_RE}">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group($css:SYMBOL_RE_ident)!=''">
<xsl:sequence select="regex-group($css:SYMBOL_RE_ident)"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="css:parse-string(regex-group($css:SYMBOL_RE_string))/@value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:function name="css:counter-value" as="xs:integer?">
<xsl:param name="name" as="xs:string"/>
<xsl:param name="context" as="element()"/>
<xsl:variable name="reset-x" as="xs:string" select="concat('counter-reset-',$name)"/>
<xsl:variable name="set-x" as="xs:string" select="concat('counter-set-',$name)"/>
<xsl:variable name="increment-x" as="xs:string" select="concat('counter-increment-',$name)"/>
<xsl:variable name="creator" as="element()?">
<xsl:variable name="candidates" as="element()*" select="$context/ancestor-or-self::*/(self::*|preceding-sibling::*)"/>
<xsl:sequence select="if ($candidates[@css:*[local-name()=$reset-x]]) then ($candidates[@css:*[local-name()=$reset-x]])[last()] else ($candidates[@css:*[local-name()=($set-x,$increment-x)]])[1]"/>
</xsl:variable>
<xsl:if test="$creator">
<xsl:variable name="scope" as="element()*" select="$context/(preceding::*|ancestor-or-self::*) intersect $creator/(self::*|following-sibling::*)/descendant-or-self::* except $creator/(descendant::*|following::*)[@css:*[local-name()=$reset-x]] /(self::*|following-sibling::*)/descendant-or-self::*"/>
<xsl:variable name="last-set" as="element()" select="($creator|$scope[@css:*[local-name()=$set-x]])[last()]"/>
<xsl:sequence select="sum(($last-set/@css:*[local-name()=($reset-x,$set-x,$increment-x)][1] |($scope intersect $context/(self::*|preceding::*|ancestor::*) intersect $last-set/(descendant::*|following::*)) /@css:*[local-name()=$increment-x]) /xs:integer(number(.)))"/>
</xsl:if>
</xsl:function>
<xsl:function name="pxi:counter-representation-alphabetic" as="xs:string">
<xsl:param name="number" as="xs:integer"/>
<xsl:param name="symbols" as="xs:string*"/>
<xsl:variable name="base" as="xs:integer" select="count($symbols)"/>
<xsl:sequence select="if ($number > $base) then concat(pxi:counter-representation-alphabetic(($number - 1) idiv $base, $symbols), $symbols[1 + (($number - 1) mod $base)]) else $symbols[$number]"/>
</xsl:function>
<xsl:function name="pxi:counter-representation-numeric" as="xs:string">
<xsl:param name="number" as="xs:integer"/>
<xsl:param name="symbols" as="xs:string*"/>
<xsl:variable name="base" as="xs:integer" select="count($symbols)"/>
<xsl:sequence select="if ($number >= $base) then concat(pxi:counter-representation-numeric($number idiv $base, $symbols), $symbols[1 + ($number mod $base)]) else $symbols[1 + $number]"/>
</xsl:function>
<xsl:function name="pxi:counter-representation-additive" as="xs:string?">
<xsl:param name="number" as="xs:integer"/>
<xsl:param name="weights" as="xs:integer*"/>
<xsl:param name="symbols" as="xs:string*"/>
<xsl:choose>
<xsl:when test="$number=0 and 0=$weights">
<xsl:sequence select="$symbols[index-of($weights, 0)]"/>
</xsl:when>
<xsl:when test="count($weights) > 0">
<xsl:variable name="rest-number" as="xs:integer" select="if ($weights[1]=0) then $number else $number mod $weights[1]"/>
<xsl:variable name="rest" as="xs:string?" select="if ($rest-number=0) then '' else pxi:counter-representation-additive( $rest-number, $weights[position()>1], $symbols[position()>1])"/>
<xsl:if test="exists($rest)">
<xsl:sequence select="if ($weights[1]=0) then $rest else string-join(( for $x in 1 to ($number idiv $weights[1]) return $symbols[1], $rest),'')"/>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:function>
<xsl:function name="css:counter-style" as="element(css:counter-style)">
<xsl:param name="name-or-inline" as="xs:string"/>
<xsl:analyze-string select="$name-or-inline" regex="^({$css:COUNTER_STYLE_RE})$">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1 + $css:COUNTER_STYLE_RE_name)!=''">
<xsl:sequence select="css:named-counter-style(regex-group(1 + $css:COUNTER_STYLE_RE_name))"/>
</xsl:when>
<xsl:otherwise>
<css:counter-style system="{if (not(regex-group(1 + $css:COUNTER_STYLE_RE_symbols_type)='')) then regex-group(1 + $css:COUNTER_STYLE_RE_symbols_type) else 'symbolic'}" symbols="{regex-group(1 + $css:COUNTER_STYLE_RE_symbols)}" prefix="" suffix=" " fallback="decimal" negative="-" text-transform="auto"/>
</xsl:otherwise>
</xsl:choose>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:template name="css:counter-representation" as="xs:string*">
<xsl:param name="value" as="xs:integer" required="yes"/>
<xsl:param name="style" as="element()" required="yes"/>
<xsl:param name="with-prefix-suffix" as="xs:boolean" select="false()"/>
<xsl:variable name="system" as="xs:string" select="$style/@system"/>
<xsl:variable name="symbols" as="xs:string*" select="css:parse-symbols($style/@symbols)"/>
<xsl:variable name="formatted-value" as="xs:string?">
<xsl:choose>
<xsl:when test="$system='cyclic'">
<xsl:sequence select="$symbols[1 + (($value - 1) mod count($symbols))]"/>
</xsl:when>
<xsl:when test="$system='fixed'">
<xsl:if test="$value >= 1 and $value <= count($symbols)">
<xsl:sequence select="$symbols[$value]"/>
</xsl:if>
</xsl:when>
<xsl:when test="$system='symbolic'">
<xsl:if test="$value >= 1">
<xsl:sequence select="string-join( for $x in 1 to 1 + (($value - 1) idiv count($symbols)) return $symbols[1 + (($value - 1) mod count($symbols))], '')"/>
</xsl:if>
</xsl:when>
<xsl:when test="$system='alphabetic'">
<xsl:if test="$value >= 1">
<xsl:sequence select="pxi:counter-representation-alphabetic($value, $symbols)"/>
</xsl:if>
</xsl:when>
<xsl:when test="$system='numeric'">
<xsl:sequence select="concat( if ($value >= 0) then '' else $style/@negative, pxi:counter-representation-numeric(abs($value), $symbols))"/>
</xsl:when>
<xsl:when test="$system='additive'">
<xsl:if test="$value >= 0">
<xsl:variable name="additive-symbols" as="xs:string*" select="tokenize($style/@additive-symbols,',')"/>
<xsl:sequence select="pxi:counter-representation-additive( $value, for $x in $additive-symbols return xs:integer(number(replace($x,'^\s*([1-9][0-9]*)\s.*$','$1'))), css:parse-symbols(string-join( for $x in $additive-symbols return replace($x,'^\s*[1-9][0-9]*',' '), '')))"/>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$formatted-value">
<xsl:variable name="formatted-value" as="xs:string" select="if ($with-prefix-suffix) then concat($style/@prefix,$formatted-value,$style/@suffix) else $formatted-value"/>
<xsl:variable name="text-transform" as="xs:string" select="$style/@text-transform"/>
<xsl:sequence select="($formatted-value,$text-transform)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="style" as="element()">
<xsl:for-each select="css:named-counter-style($style/@fallback)">
<xsl:copy>
<xsl:sequence select="@* except (@prefix|@suffix)"/>
<xsl:sequence select="$style/(@prefix|@suffix)"/>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<xsl:call-template name="css:counter-representation">
<xsl:with-param name="value" select="$value"/>
<xsl:with-param name="style" select="$style"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="css:counter">
<xsl:param name="name" as="xs:string" required="yes"/>
<xsl:param name="style" as="xs:string?" select="()"/>
<xsl:param name="context" as="element()" select="."/>
<xsl:param name="default-marker-contents" as="xs:boolean" select="false()"/>
<xsl:variable name="value" as="xs:integer?" select="css:counter-value($name, $context)"/>
<xsl:if test="exists($value)">
<xsl:choose>
<xsl:when test="$style and $style='none'">
<xsl:sequence select="('','none')"/>
</xsl:when>
<xsl:when test="$style">
<xsl:call-template name="css:counter-representation">
<xsl:with-param name="value" select="$value"/>
<xsl:with-param name="style" select="css:counter-style($style)"/>
<xsl:with-param name="with-prefix-suffix" select="$default-marker-contents"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>