Skip to content

Instantly share code, notes, and snippets.

@grantmacken
Last active January 4, 2016 11:09
Show Gist options
  • Save grantmacken/8613063 to your computer and use it in GitHub Desktop.
Save grantmacken/8613063 to your computer and use it in GitHub Desktop.
base60 in xquery. Look at shortURLB60.xq first
xquery version "3.0";
let $createShortDate := function ($date){
let $nYear := substring(format-date($date, "[Y]", 'en', (), ()), 3, 4)
let $nDaysOfYear := format-date($date, "[d]", 'en', (), ())
let $padDaysOfYear :=
if( string-length($nDaysOfYear) = 1) then ( '0' || '0' || $nDaysOfYear )
else if( string-length($nDaysOfYear) = 2) then ( '0' || $nDaysOfYear )
else($nDaysOfYear)
let $nStr := $nYear || $padDaysOfYear
return $nStr
}
let $base60Chars :=
let $seq1 := (0 to 9)
let $seq2 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('A') to string-to-codepoints('H'))
let $seq3 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('J') to string-to-codepoints('N'))
let $seq4 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('P') to string-to-codepoints('Z'))
let $seq5 := ('_')
let $seq6 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('a') to string-to-codepoints('k'))
let $seq7 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('m') to string-to-codepoints('z'))
return ($seq1, $seq2, $seq3, $seq4, $seq5 , $seq6, $seq7)
let $base := count($base60Chars)
let $encode := function ($n){
let $seqChars := $base60Chars
let $getRemainder := function($n){
if($n gt 59 ) then (($n mod xs:integer($base)) + 1)
else($n + 1)
}
let $getChar := function($n){$seqChars[xs:integer($getRemainder($n))]}
let $nextN := function($n){
($n - xs:integer($getRemainder($n))) div xs:integer($base)}
let $seqNth := ( xs:integer($nextN($nextN($n))), xs:integer($nextN($n)) , xs:integer($n) )
return
string-join(map(function($n){$seqChars[xs:integer($getRemainder($n))]}, $seqNth),'')
}
let $decode := function ($strB60){
let $seqDecode :=
map(function( $codePoint ){
let $c := xs:integer($codePoint)
return
if ($c >= 48 and $c <= 57 ) then ($c - 48)
else if ($c >= 65 and $c <= 72 ) then ($c - 55)
else if ($c eq 73 or $c eq 108 ) then (1)
else if ($c >= 74 and $c <= 78 ) then ($c - 56)
else if ($c eq 79 ) then (0)
else if ($c >= 80 and $c <= 90 ) then ($c - 57)
else if ($c eq 95 ) then (34)
else if ($c >= 97 and $c <= 107 ) then ($c - 62)
else if ($c >= 109 and $c <= 122 ) then ($c - 63)
else(0)
},
(map(function($ch){string-to-codepoints($ch)}, (for $ch in string-to-codepoints($strB60)
return codepoints-to-string($ch)))
))
let $tot := function($n2, $c){xs:integer(($base * $n2) + $c + 1)}
let $n2 := 0
let $dc1 := $tot($n2, $seqDecode[1])
let $dc2 := $tot($dc1, $seqDecode[2])
let $decoded := $tot($dc2, $seqDecode[3] -1 )
let $yr := '20' || substring($decoded, 1, 2)
let $yrStart := xs:date($yr || string('-01-01'))
let $dysInYr := substring($decoded, 3, 6)
let $duration := xs:dayTimeDuration("P" || string(xs:integer($dysInYr)- 1) || "D")
let $decodedDate := xs:date($yrStart + $duration)
let $formatedDate := format-date($decodedDate, "[Y0001]/[M01]/[D01]", 'en', (), ())
return $formatedDate
}
(: TEST
Random date via current-date + duration
encode decode
:)
let $strDuration := xs:dayTimeDuration("P" || string(xs:integer(util:random(1000))- 1) || "D")
let $date := current-date() + $strDuration
let $shortDate := $createShortDate($date)
let $encoded := $encode(xs:integer($shortDate))
let $decoded := $decode($encoded)
return
(
('date: '|| $date ),
('$shortDate: '|| $shortDate ),
('$base60Chars: '|| string-join($base60Chars) ),
('$encoded: '|| $encoded ),
('$decoded: '|| $decoded ),
('$strDuration: '|| current-date() + $strDuration )
)
<target name="get-short-link">
<property name="q_encode">
xquery version "3.0";
let $encode := function ($n){
let $seq1 := (0 to 9)
let $seq2 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('A') to string-to-codepoints('H'))
let $seq3 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('J') to string-to-codepoints('N'))
let $seq4 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('P') to string-to-codepoints('Z'))
let $seq5 := ('_')
let $seq6 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('a') to string-to-codepoints('k'))
let $seq7 := map(function($x) { codepoints-to-string($x) }, string-to-codepoints('m') to string-to-codepoints('z'))
let $seqChars := ($seq1, $seq2, $seq3, $seq4, $seq5 , $seq6, $seq7)
let $base := count($seqChars)
let $getRemainder := function($n){
if($n gt 59 ) then (($n mod xs:integer($base)) + 1)
else($n + 1)
}
let $getChar := function($n){$seqChars[xs:integer($getRemainder($n))]}
let $nextN := function($n){
($n - xs:integer($getRemainder($n))) div xs:integer($base)}
let $seqNth := ( xs:integer($nextN($nextN($n))), xs:integer($nextN($n)) , xs:integer($n) )
return
string-join(map(function($n){$seqChars[xs:integer($getRemainder($n))]}, $seqNth),'')
}
return
$encode(${n})
</property>
<xdb:xquery
uri="xmldb:exist://${host.local}:8080/exist/xmlrpc/db"
query="${q_encode}" user="${exist.username}"
password="${exist.password}"
outputproperty="encoded" />
<echo>${encoded}</echo>
</target>
xquery version "3.0";
declare default element namespace "http://www.w3.org/2005/Atom";
declare variable $exist:path external;
declare variable $exist:resource external;
declare variable $exist:controller external;
declare variable $exist:prefix external;
declare variable $exist:root external;
import module namespace xmldb="http://exist-db.org/xquery/xmldb";
if (matches($exist:path ,'^/[0-9A-HJ-NP-Z_a-km-z]{3}[0-9]{1,2}\.html$')) then(
let $strID := replace($exist:path, '^/([0-9A-HJ-NP-Z_a-km-z]{3}[0-9]{1,2})\.html$', '$1')
let $strB60 := replace($exist:path, '^/([0-9A-HJ-NP-Z_a-km-z]{3})[0-9]{1,2}\.html$', '$1')
let $base := 60
(: The entry point is $strB60 :)
let $seqDecode :=
map(function( $codePoint ){
let $c := xs:integer($codePoint)
return
if ($c >= 48 and $c <= 57 ) then ($c - 48)
else if ($c >= 65 and $c <= 72 ) then ($c - 55)
else if ($c eq 73 or $c eq 108 ) then (1)
else if ($c >= 74 and $c <= 78 ) then ($c - 56)
else if ($c eq 79 ) then (0)
else if ($c >= 80 and $c <= 90 ) then ($c - 57)
else if ($c eq 95 ) then (34)
else if ($c >= 97 and $c <= 107 ) then ($c - 62)
else if ($c >= 109 and $c <= 122 ) then ($c - 63)
else(0)
},
(map(function($ch){string-to-codepoints($ch)}, (for $ch in string-to-codepoints($strB60)
return codepoints-to-string($ch)))
))
let $tot := function($n2, $c){xs:integer(($base * $n2) + $c + 1)}
let $n2 := 0
let $dc1 := $tot($n2, $seqDecode[1])
let $dc2 := $tot($dc1, $seqDecode[2])
let $decoded := $tot($dc2, $seqDecode[3] -1 )
let $yr := '20' || substring($decoded, 1, 2)
let $yrStart := xs:date($yr || string('-01-01'))
let $dysInYr := substring($decoded, 3, 6)
let $duration := xs:dayTimeDuration("P" || string(xs:integer($dysInYr)- 1) || "D")
let $decodedDate := xs:date($yrStart + $duration)
let $formatedDate := format-date($decodedDate, "[Y0001]/[M01]/[D01]", 'en', (), ())
let $colPath := concat( $exist:root , $exist:controller , '/data/archive/' , $formatedDate )
let $redirect :=
if( xmldb:collection-available( $colPath ) ) then (
if( exists(xmldb:xcollection($colPath)//id[contains(., $strID)] )) then (
xmldb:xcollection($colPath)//*[id[contains(., $strID)]]/link[@rel="alternate"]/@href/string()
)
else( 'http://' || $exist:controller || '/' || 'collection-not-available' || '/' || $strB60 || '/' || $strID || '/' || $formatedDate )
)
else( 'http://' || $exist:controller || '/' || 'id-not-found' || '/' || $strB60 || '/' || $strID || '/' || $formatedDate )
return
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<redirect url="{$redirect}"/>
</dispatch>
)
else if (ends-with($exist:resource, ".html")) then
let $template-pages := '/templates/pages/'
let $template-posts := '/templates/posts/'
let $collection := if( matches($exist:path ,'^/index.html$'))then ('home')
else(tokenize($exist:path, '/')[2])
let $colURL :=
if( matches( $exist:path , '^/archive/index.html$')) then (
$exist:controller || $template-posts || 'feed' || '.html'
)
else if( contains( $exist:path , 'archive/' )) then (
$exist:controller || $template-posts || 'entry' || '.html'
)
else(
$exist:controller || $template-pages || $collection || '.html'
)
let $errorURL := $exist:controller || $template-pages || 'error.html'
let $viewURL := $exist:controller || '/modules/view.xql'
return
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<forward method="get" url="{$colURL}" />
<view>
<forward url="{$viewURL}">
<add-parameter name="exist-root" value="{$exist:root}" />
<add-parameter name="exist-prefix" value="{$exist:prefix}" />
<add-parameter name="exist-controller" value="{$exist:controller}" />
<add-parameter name="exist-resource" value="{$exist:resource}" />
<add-parameter name="exist-path" value="{$exist:path}" />
</forward>
</view>
<error-handler>
<forward method="get" url="{$errorURL}" />
<forward url="{$viewURL}" />
</error-handler>
</dispatch>
else
<dispatch xmlns="http://exist.sourceforge.net/NS/exist">
<cache-control cache="yes" />
</dispatch>
@grantmacken
Copy link
Author

For creating short-urls for tweets etc. Origin url based on date 'year/month/day'
will become 3 char, the total uri path can become just 4 chars the last char being the nth post of the day
based on tantek base 60 http://tantek.pbworks.com/w/page/19402946/NewBase60.

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