[xquery-talk] XPath/XQuery equivalent of xsl:number?
G. Ken Holman
gkholman at CraneSoftwrights.com
Thu Nov 17 16:53:14 PST 2011
At 2011-11-17 19:14 -0500, Michael Sokolov wrote:
>You might also someday be interested in the inverse function (roman
>numeral to decimal); here is what we use. It might be interesting
>for the group to compare the iterative approach here with the
>recursive approach to a similar problem in Ken's version?
Interesting thought, Mike!
>declare namespace ifp="http://www.ifactory.com/press";
>
>define function ifp:roman-number-to-decimal ($roman-number as xs:string)
>{
> let $roman-tokens := <roman-tokens>
><tok sym='M'>1000</tok>
><tok sym='D'>500</tok>
><tok sym='C'>100</tok>
><tok sym='L'>50</tok>
><tok sym='X'>10</tok>
><tok sym='V'>5</tok>
><tok sym='I'>1</tok>
></roman-tokens>
> let $l := string-length($roman-number)
> return sum (
> for $i in (0 to $l - 1)
> let $t := substring($roman-number, $l - $i, 1)
> let $s := substring($roman-number, $l - $i + 1, 1)
> let $tv := number($roman-tokens/tok[@sym=$t])
> let $sv := number($roman-tokens/tok[@sym=$s])
> return if ($sv and $sv gt $tv) then $tv * -1 else number($tv)
> )
>};
I just modified my module as below in order to offer the inverse of
Roman numeral to decimal, using the same lookup table as I use for
the initial direction. Interestingly, the solution has very much the
same shape!
. . . . . . . . . . . . Ken
xquery version "1.0";
(:
A library to transform a number less than 4000 to a sequence of
Roman digits.
Crane Softwrights Ltd. XQuery Training
:)
module namespace n2r = "urn:X-Crane:n2roman";
(:the basis of transformation is a series of strings for components:)
declare variable $n2r:values as element(value)+ :=
(
<value num="1" char="I" />,
<value num="4" char="IV"/>,
<value num="5" char="V" />,
<value num="9" char="IX"/>,
<value num="10" char="X" />,
<value num="40" char="XL"/>,
<value num="50" char="L" />,
<value num="90" char="XC"/>,
<value num="100" char="C" />,
<value num="400" char="CD"/>,
<value num="500" char="D" />,
<value num="900" char="CM"/>,
<value num="1000" char="M" />
);
(:return the concatenation of strings by continuous reduction:)
declare function n2r:n2roman ( $num as xs:integer ) as xs:string
{
(:as long as we have a number, keep going:)
if ( $num ) then
(:reduce by the largest number that has a string value:)
for $val in $n2r:values[@num <= $num][fn:last()] return
(:using the highest value:)
fn:concat( $val/@char,n2r:n2roman( $num - xs:integer( $val/@num ) ) )
(:nothing left:)
else ""
};
(:return the sum of numbers by continuous addition:)
declare function n2r:roman2n ( $str as xs:string ) as xs:integer
{
(:as long as we have a string, keep going:)
if ( $str ) then
(:reduce by the largest number that has a string value:)
for $val in $n2r:values[starts-with($str, at char)][fn:last()] return
(:using the highest value:)
xs:integer( $val/@num ) + n2r:roman2n(substring-after($str,$val/@char))
(:nothing left:)
else 0
};
(:test all numbers up to but not including 4000:)
declare function n2r:test ( ) as xs:integer*
{
for $each in 1 to 3999 return if( $each != n2r:roman2n(n2r:n2roman($each)) )
then $each else ()
};
(:end of file:)
--
Contact us for world-wide XML consulting and instructor-led training
Free 5-hour video lecture: XSLT/XPath 1.0 & 2.0 http://ude.my/t37DVX
Crane Softwrights Ltd. http://www.CraneSoftwrights.com/q/
G. Ken Holman mailto:gkholman at CraneSoftwrights.com
Google+ profile: https://plus.google.com/116832879756988317389/about
Legal business disclaimers: http://www.CraneSoftwrights.com/legal
More information about the talk
mailing list