[xquery-talk] XPath/XQuery equivalent of xsl:number?
Joe Wicentowski
joewiz at gmail.com
Fri Nov 18 07:25:36 PST 2011
Thanks everyone for your helpful ideas!
Joe
Sent from my iPhone
On Nov 17, 2011, at 7:53 PM, "G. Ken Holman" <gkholman at cranesoftwrights.com> wrote:
> 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
>
> _______________________________________________
> talk at x-query.com
> http://x-query.com/mailman/listinfo/talk
More information about the talk
mailing list