1
0
Fork 0
pdfbox/src/lib/bookpages.xqm
2024-04-03 12:12:32 +01:00

63 lines
2 KiB
Text

xquery version '3.1';
(:~ describe book page numbers as sequence of ranges, similar to PDF pagelabels
@author quodatum
:)
module namespace bookpages = 'urn:bookpages';
(:~ Invisible-xml grammar to parse custom pagelabel representation :)
declare variable $bookpages:grammar:="
book: pagecount,'#',range,(-',', range)*.
pagecount:['0'-'9']+.
range: s,from?,s,type,s,prefix?,s,offset?.
@from: ['0'-'9']+. { pageIndex }
@type: ['C'|'D'|'R'|'r'|'A'|'a'|'w'].
@prefix: -':',~[',']+.
@offset: -'@',['0'-'9']+.
-s: ([Zs]; #9; #a; #d)*. {Optional whitespace}
";
(:~
page number range in given style
:)
declare function bookpages:span($type as xs:string,$length as xs:integer,$first as xs:integer)
as xs:string*{
let $r:=$first to $first+$length
return switch ($type)
case "D" return $r!format-integer(.,"1")
case "r" return $r!format-integer(.,"i")
case "R" return $r!format-integer(.,"I")
case "C" return "Cover"
default return $r!format-integer(.,$type)
};
(:~ pagelabels from text:)
declare function bookpages:expand($pages as xs:string)
as xs:string*{
let $x:=bookpages:parse($pages)
let $last:=head($x)=>xs:integer()
return hof:until(
function($m){ empty($m?ranges) or count($m?result)eq $last },
function($m){
let $range:=head($m?ranges)=>trace("SS")
let $start:=if($range/@offset)then xs:integer($range/@offset) else 1
let $end:=($m?ranges[2]/xs:integer(@from)-1) otherwise $last
let $length:=$end -count($m?result)-1
let $span:=bookpages:span($range/@type,$length,$start)
let $span:=if($range/@prefix)then $span!concat($range/@prefix,.) else $span
return map {
'ranges': tail($m?ranges),
'result': ($m?result, $span)
}},
(: initial input = grammar ranges :)
map { 'ranges': tail($x) , 'result': () }
)?result
};
(:~ parse pagenumber description to xml :)
declare function bookpages:parse($pages as xs:string)
as element(range)*{
invisible-xml($bookpages:grammar)($pages)/*
};