Skip to content

Instantly share code, notes, and snippets.

@ryanjdew
Last active October 19, 2018 21:01
Show Gist options
  • Save ryanjdew/2504057 to your computer and use it in GitHub Desktop.
Save ryanjdew/2504057 to your computer and use it in GitHub Desktop.
XQuery 3.0 functions in XQuery 1.0
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare function local:has-children($node as node()?) as xs:boolean {
fn:exists($node/child::node())
};
let $doc := document {
element html:html {
element html:head {
comment {"This is a comment"},
element html:title {"Title"},
comment {"This is comment 2"}
},
element html:body {
element html:div {
attribute class {"class"}
}
}
}
}
return (
local:has-children($doc/html:html/html:head/html:title),
local:has-children($doc/html:html/html:head),
local:has-children($doc/html:html/html:body/html:div)
)
xquery version "1.0-ml";
declare function local:head($args as item()*) as item()? {
$args[1]
};
local:head(fn:reverse(1 to 15))
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare function local:innermost($nodes as node()*) as node()* {
$nodes except $nodes/ancestor::node()
};
let $doc := document {
element html:html {
element html:head {
comment {"This is a comment"},
element html:title {"Title"},
comment {"This is comment 2"}
},
element html:body {
element html:div {
attribute class {"class"}
}
}
}
}
return
local:innermost(($doc/html:html/html:head/html:title,
$doc/html:html/html:head,
$doc/html:html/html:body/html:div,
$doc/html:html/html:body,
$doc/html:html/html:body/html:div/@class))
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare function local:outermost($nodes as node()*) as node()* {
$nodes except ($nodes/descendant::node(),$nodes/descendant-or-self::node()/attribute::node())
};
let $doc := document {
element html:html {
element html:head {
comment {"This is a comment"},
element html:title {"Title"},
comment {"This is comment 2"}
},
element html:body {
element html:div {
attribute class {"class"}
}
}
}
}
return (
local:outermost(($doc/html:html/html:head/html:title,
$doc/html:html/html:head,
$doc/html:html/html:body/html:div,
$doc/html:html/html:body,
$doc/html:html/html:body/html:div/@class))
)
xquery version "1.0-ml";
declare namespace html = "http://www.w3.org/1999/xhtml";
declare function local:path($arg as node()?) as xs:string {
if (fn:exists($arg) and fn:root($arg) instance of document-node())
then
fn:string-join(
$arg/ancestor-or-self::node()/(
typeswitch(.)
case element() return
let $ns := fn:namespace-uri(.), $name := fn:local-name(.), $qname := fn:QName($ns,$name)
return fn:concat('Q{',$ns,'}',$name,'[',(fn:count(./preceding-sibling::node()[fn:node-name(.) eq $qname]) + 1),']')
case attribute() return
let $ns := fn:namespace-uri(.), $name := fn:local-name(.)
return fn:string-join(('@',if ($ns eq "") then () else ('Q{', $ns,'}'),$name),'')
case text() return
fn:concat('text()[',(fn:count(./preceding-sibling::text()) + 1),']')
case comment() return
fn:concat('comment()[',(fn:count(./preceding-sibling::comment()) + 1),']')
case processing-instruction() return
let $name := fn:local-name(.)
return fn:concat('processing-instruction(',$name,')[',(fn:count(./preceding-sibling::processing-instruction()[fn:local-name(.) eq $name]) + 1),']')
case document-node() return
''
default return ()
),
"/")
else fn:error(fn:QName("http://www.w3.org/2005/xqt-errors","err:FODC0001"),"No context document.")
};
declare function local:unpath($arg as xs:string, $node as node()) as node()? {
local:unpath-step(fn:tokenize(fn:replace($arg,'((^|(^[^/])|(\]))/)','$2|~|'), '\|~\|')[. ne ''], $node)
};
declare function local:unpath-step($steps as xs:string*, $node as node()) as node()? {
if (empty($steps))
then $node
else
let $cur-step := head($steps)
return (
if (matches($cur-step,'^@'))
then
let $qname := if (contains($cur-step,":"))
then QName(replace($cur-step,'^@Q\{(.*)\}:.*','$1'),substring-after($cur-step,':'))
else QName("",substring-after($cur-step,'@'))
return $node/attribute()[node-name(.) eq $qname]
else if (matches($cur-step,'^Q\{.*\}.*'))
then
let $qname := QName(replace($cur-step,'^Q\{(.*)\}.*','$1'),replace($cur-step,'^Q\{.*\}(.*)\[[0-9]+\]$','$1')),
$position := number(replace($cur-step,'^Q\{.*\}.*\[([0-9]+)\]$','$1'))
return (local:unpath-step(tail($steps), ($node/element()[node-name(.) eq $qname])[$position]))
else if (matches($cur-step,'^comment\(\)\[[0-9]+\]$'))
then
let $position := number(replace($cur-step,'^comment\(\)\[([0-9]+)\]$','$1'))
return $node/comment()[$position]
else if (matches($cur-step,'^text\(\)\[[0-9]+\]$'))
then
let $position := number(replace($cur-step,'^text\(\)\[([0-9]+)\]$','$1'))
return $node/text()[$position]
else if (matches($cur-step,'^processing-instruction\(.*\)\[[0-9]+\]$'))
then
let $qname := QName("",replace($cur-step,'^processing-instruction\((.*)\)\[[0-9]+\]$','$1')),
$position := number(replace($cur-step,'^processing-instruction\(.*\)\[([0-9]+)\]$','$1'))
return ($node/processing-instruction()[node-name(.) eq $qname])[$position]
else fn:error(xs:QName('UNPATH'), "Invalid unpath exception", $cur-step)
)
};
let $doc := document {
element html:html {
<?other-instruction do-this?>,
<?instruction do-this?>,
element html:head {
comment {"This is a comment"},
element html:title {"Title"},
comment {"This is comment 2"}
},
element html:body {
element html:div {
attribute class {"class"}
}
}
}
}
return (
for $node in $doc//node()/(@*|.)
return local:path($node),
every $node in $doc//node()/(@*|.)
satisfies local:unpath(local:path($node), $doc) is $node
)
xquery version "1.0-ml";
declare function local:tail($args as item()*) as item()* {
fn:subsequence($args, 2)
};
local:tail(fn:reverse(1 to 15))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment