<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:pf="http://www.daisy.org/ns/pipeline/functions" xmlns:f="http://www.daisy.org/ns/pipeline/internal-functions" version="2.0" exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:function name="pf:numeric-is-roman" as="xs:boolean">
<xsl:param name="roman" as="xs:string"/>
<xsl:value-of select="not((for $char in string-to-codepoints($roman) return contains('MDCLXVI',upper-case(codepoints-to-string($char)))) = false())"/>
</xsl:function>
<xsl:function name="pf:numeric-roman-to-decimal" as="xs:integer">
<xsl:param name="roman" as="xs:string"/>
<xsl:variable name="hindu-sequence" select="for $char in string-to-codepoints($roman) return number(replace(replace(replace(replace(replace(replace(replace(upper-case(codepoints-to-string($char)),'I','1'),'V','5'),'X','10'),'L','50'),'C','100'),'D','500'),'M','1000'))"/>
<xsl:variable name="hindu-sequence-signed" select="for $i in 1 to count($hindu-sequence) return if (subsequence($hindu-sequence,$i+1) > $hindu-sequence[$i]) then -$hindu-sequence[$i] else $hindu-sequence[$i]"/>
<xsl:value-of select="sum($hindu-sequence-signed)"/>
</xsl:function>
<xsl:function name="pf:numeric-decimal-to-roman" as="xs:string">
<xsl:param name="hindu" as="xs:integer"/>
<xsl:variable name="hindu-sequence" select="reverse(for $num in string-to-codepoints(string($hindu)) return codepoints-to-string($num))"/>
<xsl:variable name="dec1" select="if ($hindu-sequence[1] = '1') then 'I' else if ($hindu-sequence[1] = '2') then 'II' else if ($hindu-sequence[1] = '3') then 'III' else if ($hindu-sequence[1] = '4') then 'IV' else if ($hindu-sequence[1] = '5') then 'V' else if ($hindu-sequence[1] = '6') then 'VI' else if ($hindu-sequence[1] = '7') then 'VII' else if ($hindu-sequence[1] = '8') then 'VIII' else if ($hindu-sequence[1] = '9') then 'IX' else ''"/>
<xsl:variable name="dec2" select="if ($hindu-sequence[2] = '1') then 'X' else if ($hindu-sequence[2] = '2') then 'XX' else if ($hindu-sequence[2] = '3') then 'XXX' else if ($hindu-sequence[2] = '4') then 'XL' else if ($hindu-sequence[2] = '5') then 'L' else if ($hindu-sequence[2] = '6') then 'LX' else if ($hindu-sequence[2] = '7') then 'LXX' else if ($hindu-sequence[2] = '8') then 'LXXX' else if ($hindu-sequence[2] = '9') then 'XC' else ''"/>
<xsl:variable name="dec3" select="if ($hindu-sequence[3] = '1') then 'C' else if ($hindu-sequence[3] = '2') then 'CC' else if ($hindu-sequence[3] = '3') then 'CCC' else if ($hindu-sequence[3] = '4') then 'CD' else if ($hindu-sequence[3] = '5') then 'D' else if ($hindu-sequence[3] = '6') then 'DC' else if ($hindu-sequence[3] = '7') then 'DCC' else if ($hindu-sequence[3] = '8') then 'DCCC' else if ($hindu-sequence[3] = '9') then 'CM' else ''"/>
<xsl:variable name="dec4" select="string-join(for $i in 1 to xs:integer(concat('0',string-join(reverse(subsequence($hindu-sequence,4)),''))) return 'M','')"/>
<xsl:value-of select="concat($dec4,$dec3,$dec2,$dec1)"/>
</xsl:function>
<xsl:function name="pf:numeric-alpha-to-decimal" as="xs:integer">
<xsl:param name="alpha" as="xs:string"/>
<xsl:sequence select="string-to-codepoints($alpha)-96"/>
</xsl:function>
<xsl:function name="pf:numeric-decimal-to-alpha" as="xs:string">
<xsl:param name="decimal" as="xs:integer"/>
<xsl:value-of select="string-join(f:numeric-decimal-to-alpha-part($decimal,()),'')"/>
</xsl:function>
<xsl:function name="f:numeric-decimal-to-alpha-part" as="xs:string*">
<xsl:param name="remainder" as="xs:integer"/>
<xsl:param name="result" as="xs:string*"/>
<xsl:choose>
<xsl:when test="$remainder <= 0">
<xsl:sequence select="$result"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="f:numeric-decimal-to-alpha-part( xs:integer(floor($remainder div 26)), (codepoints-to-string(($remainder mod 26) + 96), $result))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>