//(node()|@*)!path()
//node()!(.,@*)!path(.)
Special thanks to Reece H. Dunn for pointing me towards fn:path
//(node()|@*)!path()
//node()!(.,@*)!path(.)
Special thanks to Reece H. Dunn for pointing me towards fn:path
(: thanks to Reece H. Dunn for hinting at the fn:path function :) | |
//node()!(.,@*)!path() |
//node()!(.,@*)!string-join(tail((ancestor::*,.))!(let$n:=name(.)let$t:=typeswitch(.)case attribute() | |
return -2 caseelement() return -1 casecomment() return 1 casetext() return 2 default return 3 return | |
if($t>0)then let$e:=(["comment",preceding-sibling::comment()],["text",preceding-sibling::text()],["node",1])[$t]return$e?1||"()["||count($e?2)+1||"]"else | |
[$n||"["||count(preceding-sibling::*[name(.)=$n])+1||"]","@"||name(.)](-$t)),"/")!concat("/",.) |
//node()!(.,@*)!string-join(tail((ancestor::*,.))!(let$n:=name(.)let$t:=typeswitch(.)case | |
attribute()return(-2)case element()return(-1)case comment()return(1)case text()return(2)default return(3)return if($t>0)then | |
let$e:=(["comment",preceding-sibling::comment()],["text",preceding-sibling::text()],["node",1])[$t]return$e?1||"()["||count($e?2)+1||"]"else | |
[$n||"["||count(preceding-sibling::*[name(.)=$n])+1||"]","@"||name(.)](-$t)),"/")!concat("/",.) |
xquery version "3.1"; | |
declare namespace xpaths="http://line-o.de/ns/xpaths"; | |
declare namespace tei="http://www.tei-c.org/ns/1.0"; | |
(:~ | |
: A pure XQuery implementation of fn:path | |
:) | |
declare function xpaths:path ($node as node()) as xs:string { | |
( | |
($node/ancestor::*, $node) | |
! ( | |
let $t := | |
typeswitch(.) | |
case attribute() return -2 | |
case element() return -1 | |
case comment() return 1 | |
case text() return 2 | |
default return 3 | |
return | |
if ($t > 0) | |
then | |
let $e := ( | |
["comment", preceding-sibling::comment()], | |
["text", preceding-sibling::text()], | |
["node", 1] | |
)[$t] | |
return ``[`{$e?1}`()[`{count($e?2)+1}`]]`` | |
else | |
let $n := name(.) | |
let $qn := xs:QName(name(.)) | |
let $q := "Q{" || namespace-uri-from-QName($qn) || "}" || local-name-from-QName($qn) | |
let $i := -$t (: see https://github.com/eXist-db/exist/issues/3892 :) | |
return ( | |
``[`{$q}`[`{count(preceding-sibling::*[name(.)=$n])+1}`]]``, | |
"@" || $q )[$i] | |
) => string-join("/") | |
) | |
! concat("/", .) | |
}; | |
let $xml := document { | |
<xml> | |
<a><![CDATA[<b/>]]></a> | |
<c><d>N<!-- no comment --><e/></d></c> | |
<c xml:id="s123" a="1"><d>E<e/></d></c> | |
<c><d>M<e/></d></c> | |
<c><d>O<e/></d></c> | |
<tei:TEI /> | |
</xml> | |
} | |
let $test := | |
function ($xpath as xs:string) as item()* { | |
util:eval(concat("$xml", $xpath)) | |
} | |
return | |
$root//node() | |
! (., @*) | |
! xpaths:path(.) | |
! $test(.) |