Skip to content

Instantly share code, notes, and snippets.

@CliffordAnderson
Last active July 17, 2022 01:56
Show Gist options
  • Save CliffordAnderson/0794d8d582eb37f1adffa3b852ce19c7 to your computer and use it in GitHub Desktop.
Save CliffordAnderson/0794d8d582eb37f1adffa3b852ce19c7 to your computer and use it in GitHub Desktop.
XQuery Puzzles from Week 1, Day 5, Session 4 of the Advanced Digital Editions NEH Institute at the University of Pittsburgh
xquery version "3.1";
let $date := "July 15, 2022"
let $tokens := fn:tokenize($date, " ")
let $month :=
switch ($tokens[1])
case "January" return "01"
case "February" return "02"
case "March" return "03"
case "April" return "04"
case "May" return "05"
case "June" return "06"
case "July" return "07"
case "August" return "08"
case "September" return "09"
case "October" return "10"
case "November" return "11"
case "December" return "12"
default return "01"
let $day := $tokens[2] => translate(",","")
let $year := $tokens[3]
return xs:date($year || "-" || $month || "-" || $day )
xquery version "3.1";
for $date in ("July 15, 2022", "January 5, 2023")
let $tokens := fn:tokenize($date, " ")
let $month :=
switch ($tokens[1])
case "January" return "01"
case "February" return "02"
case "March" return "03"
case "April" return "04"
case "May" return "05"
case "June" return "06"
case "July" return "07"
case "August" return "08"
case "September" return "09"
case "October" return "10"
case "November" return "11"
default return "01"
let $day := ($tokens[2] => translate(",","")) ! (if (fn:string-length(.) < 2) then "0" || . else .)
let $year := $tokens[3]
return xs:date($year || "-" || $month || "-" || $day )
xquery version "3.1";
declare function local:char-to-int($roman as xs:string) as xs:integer {
switch ($roman)
case "I" return 1
case "V" return 5
case "X" return 10
case "L" return 50
case "C" return 100
case "D" return 500
case "M" return 1000
default return 0
};
declare function local:roman-to-integer($roman as xs:string) as xs:integer{
fn:sum(
let $symbols := string-to-codepoints($roman) ! codepoints-to-string(.) ! local:char-to-int(.)
for $symbol at $index in $symbols
return
if ($index lt fn:count($symbols))
then
let $next-symbol := $symbols[$index + 1]
return
if ($symbol ge $next-symbol) then $symbol
else -$symbol
else $symbol
)
};
local:roman-to-integer("MDXCIX")
@CliffordAnderson
Copy link
Author

CliffordAnderson commented Jul 17, 2022

Just to add to the fun, here's a solution that uses windowing. As I mentioned briefly yesterday, XQuery 3.0 added window as a clause to FLWOR expressions. A window allows you to partition your tuple streams. You can use windows to inflect your data, giving structure to data that would otherwise be flat. I use a window clause in this function to capture any pairwise Roman numerals like IV or IX.

xquery version "3.1";

declare function local:convert-roman($roman as xs:string) as xs:integer {
  fn:sum(
    let $symbols as map(xs:string, xs:integer) := map {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000 }
    let $tokens as xs:string+ := string-to-codepoints($roman) ! codepoints-to-string(.)
    let $values as xs:integer+ :=  $tokens ! $symbols(.)
    for tumbling window $w in fn:reverse($values)
        start $start when true() 
        end $end next $next when $next ge $end
    return
      typeswitch($w)
        case xs:integer return $w
        default return $w[1] - $w[2]
  )
};

local:convert-roman("DCCLXXIV")

Right now, window clauses are available in BaseX and Saxon, but not eXistDB. But hopefully, they'll be coming to eXistDB soon!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment