Hello --

Using BaseX 9.6.1 on Linux.

So I'm trying to convert a compact-ish element pattern string, delimited
with braces, back into something that looks like XML vocabulary for
readability.  (The pattern strings are being used to detect similar
structure in the content set.)

The test query (below) works fine.

Stick the functions in a module namespace, and run the real content, and I
get the "Stack Overflow: Try tail recursion?" error.  (Query plan for this
case attached.)

Nothing in the real data should be all that large.  I suspect I'm being too
clever for my own good somehow, but if anyone can tell me specifically
where I'd appreciate it.

Thanks!
Graydon

======

declare namespace fn = "http://www.w3.org/2005/xpath-functions";;

declare variable $NMToken as xs:string := '[\p{L}\p{Nd}._\-:]+';

declare function local:tag($names as xs:string*,$active as
xs:string*,$event as xs:string*) {

  let $do as xs:string := substring($event,1,1)

  return
    if (not(normalize-space($do)))
  then ()
  else if ($do eq '{')
      then (concat('<',head($names),'>'),
local:tag(tail($names),(head($names),$active),substring($event,2)))
      else (concat('</',head($active),'>'),
local:tag($names,tail($active),substring($event,2)))
};

declare function local:emitPattern($in as xs:string) as xs:string {

  let $chunked as element(fn:analyze-string-result) :=
analyze-string($in,$NMToken)
  let $names as xs:string+ := $chunked/fn:match/string()
  let $openClose as xs:string+ := $chunked/fn:non-match => string-join()

  return string-join(local:tag($names,(),$openClose))
};

let $pattern as xs:string := "{subblock{sublabel}{p}}"
let $yikes as xs:string :=
"{primaryblock{shortdesc}{table{title}{tgroup{colspec}{colspec}{colspec}{thead{row{entry{p}}{entry{p}}{entry{p}}}}{tbody{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}{row{entry{p}}{entry{p{xref}}}{entry{p}}}{row{entry{p}}{entry{p{em}}}{entry{p}}}}}}{note{p}}}"

return ($pattern,$yikes) ! local:emitPattern(.)
Error:
Stack Overflow: Try tail recursion?
Compiling:
- flatten nested single iter path: *
- rewrite iter filter to iter path: $in_2[*] -> $in_2/*
- remove type check: xs:string -> (if($in_2 instance of element()) then 
concat("{", name($in_2), (if($in_2/*) then string-join($in_2/* ! 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}getStruct(.)) else 
()), "}") else error(...
- merge: concat(base-uri($in_1), replace(path($in_1), "Q\{\}", ""))
- rewrite mixed path to fn:concat(value1,value2[,...]): 
$in_1/concat(base-uri($in_1), replace(path($in_1), "Q\{\}", "")) -> 
concat(base-uri($in_1), replace(path($in_1), "Q\{\}", ""))
- remove type check: xs:string -> concat(base-uri($in_1), replace(path($in_1), 
"Q\{\}", ""))
- inline for $key_4 in map:keys($map_3)
- simplify FLWOR expression: map:keys($map_3) ! map:entry($map_3(.), .)
- remove type check: map(xs:anyAtomicType, xs:anyAtomicType) -> 
map:merge(map:keys($map_3) ! map:entry($map_3(.), .))
- remove type check: $do_8 as xs:string
- rewrite 'eq' comparison to simplified = comparison: ($do_8 eq "{") -> ($do_8 
= "{")
- swap operands: (if(normalize-space($do_8)) then (if(($do_8 = "{")) then 
(concat("<", head($names_5), ">"), 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}tag(tail($names_5), 
(head($names_5), $active_6), su...
- inline $reuse:NMToken
- rewrite mixed path to iterative dual simple map: 
$chunked_10/fn:match/string() -> $chunked_10/fn:match ! string()
- remove type check: $openClose_12 as xs:string+
- inline let $openClose_12 := string-join($chunked_10/fn:non-match)
- inline let $names_11 as xs:string+ := $chunked_10/fn:match ! string()
- inline let $chunked_10 as element(fn:analyze-string-result) := 
analyze-string($in_9, "[\p{L}\p{Nd}._\-:]+")
- simplify FLWOR expression: (analyze-string($in_9, "[\p{L}\p{Nd}._\-:]+") 
treat as element(fn:analyze-string-result)) ! 
string-join(Q{https://precisioncontent.com/xquery/analysis/for-reuse}tag((fn:match
 ! string() treat as xs:st...
- remove type check: xs:string -> (analyze-string($in_9, "[\p{L}\p{Nd}._\-:]+") 
treat as element(fn:analyze-string-result)) ! 
string-join(Q{https://precisioncontent.com/xquery/analysis/for-reuse}tag((fn:match
 ! string() treat as xs:st...
- remove type check: xs:string -> replace($in_14, "Q\{\}", "")
- inline Q{https://precisioncontent.com/xquery/analysis/for-reuse}scrubPath#1
- remove type check: $in_34 as xs:string
- inline let $in_34 := $in_13
- simplify FLWOR expression: replace($in_13, "Q\{\}", "")
- remove type check: xs:string -> replace(replace($in_13, "Q\{\}", ""), 
"\[\p{Nd}+\]", "")
- rewrite cached filter to util:last(items): tokenize($path_15, "/")[last()] -> 
util:last(tokenize($path_15, "/"))
- inline Q{https://precisioncontent.com/xquery/analysis/for-reuse}scrubName#1
- inline let $in_35 as xs:string := util:last(tokenize($path_15, "/"))
- simplify FLWOR expression: replace(replace((util:last(tokenize($path_15, 
"/")) promote to xs:string), "Q\{\}", ""), "\[\p{Nd}+\]", "")
- remove type check: xs:string -> replace(replace((util:last(tokenize($path_15, 
"/")) promote to xs:string), "Q\{\}", ""), "\[\p{Nd}+\]", "")
- inline Q{https://precisioncontent.com/xquery/analysis/for-reuse}getName#1
- remove type check: $path_36 as xs:string
- inline let $path_36 := $in_16
- simplify FLWOR expression: replace(replace((util:last(tokenize($in_16, "/")) 
promote to xs:string), "Q\{\}", ""), "\[\p{Nd}+\]", "")
- inline Q{https://precisioncontent.com/xquery/analysis/for-reuse}scrubPath#1
- remove type check: $in_37 as xs:string
- inline let $in_37 := $in_16
- simplify FLWOR expression: replace($in_16, "Q\{\}", "")
- remove type check: element(element-info) -> <element-info> <name>{ 
replace(replace((util:last(tokenize($in_16, "/")) promote to xs:string), 
"Q\{\}", ""), "\[\p{Nd}+\]", "") }</name> <location>{ replace($in_16, "Q\{\}", 
"") }</location></element...
- open database "data"
- rewrite db:open(database[,path]) to document-node() sequence: db:open("data") 
-> (db:open-pre("data", 0), ...)
- rewrite cached filter to iter path: (db:open-pre("data", 0), 
...)[ends-with(document-uri(), ".xml")] -> (db:open-pre("data", 0), 
...)/.[ends-with(document-uri(), ".xml")]
- rewrite list to xs:string sequence: ("block", "defblock", "fnblock", 
"primaryblock", "regblock", "subblock") -> ("block", "defblock", "fnblock", 
"primaryblock", ...)
- remove type check: $interesting_19 as xs:string+
- remove type check: $pattern_22 as xs:string
- inline Q{https://precisioncontent.com/xquery/analysis/for-reuse}getLocation#1
- remove type check: $in_38 as element()
- inline let $in_38 := .
- simplify FLWOR expression: concat(base-uri(.), replace(path(.), "Q\{\}", ""))
- remove type check: $index_27 as xs:integer
- remove type check: $type2patternMap_25 as map(xs:string, xs:string)
- inline 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}invertSimpleMap#1
- remove type check: $map_39 as map(xs:anyAtomicType, xs:anyAtomicType)
- inline let $map_39 := $type2patternMap_25
- simplify FLWOR expression: map:merge(map:keys($type2patternMap_25) ! 
map:entry($type2patternMap_25(.), .))
- rewrite lookup to util:map-values(map): $map_30? * -> util:map-values($map_30)
- inline for $map_30 in $rawPatterns_20
- simplify FLWOR expression: $rawPatterns_20 ! 
map:entry($pattern2typeMap_28(map:keys(.)), util:map-values(.))
- remove type check: $found_33 as xs:integer
- inline Q{https://precisioncontent.com/xquery/analysis/for-reuse}emitPattern#1
- inline let $in_40 as xs:string := $type2patternMap_25($sp_31)
- simplify FLWOR expression: (analyze-string(($type2patternMap_25($sp_31) 
promote to xs:string), "[\p{L}\p{Nd}._\-:]+") treat as 
element(fn:analyze-string-result)) ! 
string-join(Q{https://precisioncontent.com/xquery/analysis/for-...
- inline Q{https://precisioncontent.com/xquery/analysis/for-reuse}emitLocation#1
- remove type check: $in_41 as xs:string
- inline let $in_41 := .
- simplify FLWOR expression: <element-info> <name>{ 
replace(replace((util:last(tokenize(., "/")) promote to xs:string), "Q\{\}", 
""), "\[\p{Nd}+\]", "") }</name> <location>{ replace(., "Q\{\}", "") 
}</location></element-info>
- inline let $type2locationMap_29 as map(xs:string, xs:string+) := 
map:merge($rawPatterns_20 ! map:entry($pattern2typeMap_28(map:keys(.)), 
util:map-values(.)))
- inline let $interesting_19 := ("block", "defblock", "fnblock", 
"primaryblock", ...)
- inline let $DITAcontentSet_18 as document-node()+ := (db:open-pre("data", 0), 
...)/.[ends-with(document-uri(), ".xml")]
- remove type check: $in_2 as element()?
- remove type check: $in_1 as element()
- remove type check: $map_3 as map(xs:anyAtomicType, xs:anyAtomicType)
- remove type check: $names_5 as xs:string*
- remove type check: $active_6 as xs:string*
- remove type check: $event_7 as xs:string*
- remove type check: $in_14 as xs:string
- remove type check: $in_16 as xs:string
Optimized Query:
declare function 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}getStruct($in_2) { 
(if($in_2 instance of element()) then concat("{", name($in_2), (if($in_2/*) 
then string-join($in_2/* ! 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}getStruct(.)) else 
()), "}") else error(Q{http://www.w3.org/2005/xqt-errors}XPTY0004, "Cannot 
promote empty-sequence() to xs:string: ().")) };
declare function 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}tag($names_5, 
$active_6, $event_7) { (let $do_8 := substring($event_7, 1, 1) where 
normalize-space($do_8) return (if(($do_8 = "{")) then (concat("<", 
head($names_5), ">"), 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}tag(tail($names_5), 
(head($names_5), $active_6), substring($event_7, 2))) else (concat("</", 
head($active_6), ">"), 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}tag($names_5, 
tail($active_6), substring($event_7, 2))))) };
(let $rawPatterns_20 as (map(xs:string, xs:string+))+ := (for $list_21 in 
((db:open-pre("data", 0), ...)/.[ends-with(document-uri(), ".xml")] treat as 
document-node()+)/descendant::*[(name() = ("block", "defblock", "fnblock", 
"primaryblock", ...))] let $pattern_22 := 
Q{https://precisioncontent.com/xquery/analysis/for-reuse}getStruct($list_21) 
let (: post-group :) $list_24 := $list_21 group by $pattern_23 := $pattern_22 
return map:entry($pattern_23, $list_24 ! concat(base-uri(.), replace(path(.), 
"Q\{\}", "")))) let $type2patternMap_25 := map:merge((for $pattern_26 at 
$index_27 in $rawPatterns_20 ! map:keys(.) order by $pattern_26 empty least 
return map:entry(concat("type", $index_27), $pattern_26))) let 
$pattern2typeMap_28 as map(xs:string, xs:string) := 
map:merge(map:keys($type2patternMap_25) ! map:entry($type2patternMap_25(.), .)) 
return (map:merge($rawPatterns_20 ! map:entry($pattern2typeMap_28(map:keys(.)), 
util:map-values(.))) treat as map(xs:string, xs:string+)) ! 
<structure-patterns>{ (for $sp_31 in map:keys(.) let $locations_32 as 
xs:string+ := .($sp_31) let $found_33 := count($locations_32) order by 
$found_33 descending empty least return <pattern number-found= "{ $found_33 }"> 
<designation>{ $sp_31 }</designation> <pattern>{ 
(analyze-string(($type2patternMap_25($sp_31) promote to xs:string), 
"[\p{L}\p{Nd}._\-:]+") treat as element(fn:analyze-string-result)) ! 
string-join(Q{https://precisioncontent.com/xquery/analysis/for-reuse}tag((fn:match
 ! string() treat as xs:string+), (), string-join(fn:non-match))) }</pattern> 
<locations>{ $locations_32 ! <element-info> <name>{ 
replace(replace((util:last(tokenize(., "/")) promote to xs:string), "Q\{\}", 
""), "\[\p{Nd}+\]", "") }</name> <location>{ replace(., "Q\{\}", "") 
}</location></element-info> }</locations></pattern>) }</structure-patterns>)
Query:
import module namespace reuse = 
"https://precisioncontent.com/xquery/analysis/for-reuse"; at 
'EG-structure-compare.xqm'; let $DITAcontentSet as document-node()+ := 
db:open('data')[ends-with(document-uri(),'.xml')] let $interesting as 
xs:string+ := 
('block','defblock','fnblock','primaryblock','regblock','subblock') let 
$rawPatterns as map(xs:string,xs:string+)+ := for $list in 
$DITAcontentSet/descendant::*[name() = $interesting] let $pattern as xs:string 
:= reuse:getStruct($list) group by $pattern return map:entry($pattern, $list ! 
reuse:getLocation(.)) let $type2patternMap as map(xs:string,xs:string) := 
map:merge( for $pattern at $index in $rawPatterns ! map:keys(.) order by 
$pattern return map:entry(concat('type',$index),$pattern) ) let 
$pattern2typeMap as map(xs:string,xs:string) := 
reuse:invertSimpleMap($type2patternMap) let $type2locationMap as 
map(xs:string,xs:string+) := map:merge( for $map in $rawPatterns return 
map:entry($pattern2typeMap(map:keys($map)),$map?*) ) return 
<structure-patterns>{ for $sp in map:keys($type2locationMap) let $locations as 
xs:string+ := $type2locationMap($sp) let $found as xs:integer := 
count($locations) order by $found descending return <pattern 
number-found="{$found}"> <designation>{$sp}</designation> 
<pattern>{reuse:emitPattern($type2patternMap($sp))}</pattern> 
<locations>{$locations ! reuse:emitLocation(.)}</locations> </pattern> 
}</structure-patterns>
Query Plan:
<QueryPlan compiled="true" updating="false">
  <StaticFunc name="reuse:getStruct" type="xs:string?">
    <Var name="$in" id="2" promote="true" type="item()*"/>
    <If type="xs:string?">
      <Instance of="element()" type="xs:boolean" size="1">
        <VarRef type="element()?" name="$in" id="2" promote="true"/>
      </Instance>
      <FnConcat name="concat" type="xs:string" size="1">
        <Str type="xs:string" size="1">{</Str>
        <FnName name="name" type="xs:string" size="1">
          <VarRef type="element()?" name="$in" id="2" promote="true"/>
        </FnName>
        <If type="xs:string?">
          <IterPath type="element()*">
            <VarRef type="element()?" name="$in" id="2" promote="true"/>
            <IterStep axis="child" test="*" type="element()*"/>
          </IterPath>
          <FnStringJoin name="string-join" type="xs:string" size="1">
            <DualMap type="xs:string*">
              <IterPath type="element()*">
                <VarRef type="element()?" name="$in" id="2" promote="true"/>
                <IterStep axis="child" test="*" type="element()*"/>
              </IterPath>
              <StaticFuncCall name="reuse:getStruct" tailCall="false" 
type="xs:string" size="1">
                <ContextValue type="element()" size="1"/>
              </StaticFuncCall>
            </DualMap>
          </FnStringJoin>
          <Empty type="empty-sequence()" size="0"/>
        </If>
        <Str type="xs:string" size="1">}</Str>
      </FnConcat>
      <FnError name="error" type="empty-sequence()" size="0">
        <QNm type="xs:QName" size="1">err:XPTY0004</QNm>
        <Str type="xs:string" size="1">Cannot promote empty-sequence() to 
xs:string: ().</Str>
      </FnError>
    </If>
  </StaticFunc>
  <StaticFunc name="reuse:tag" type="item()*">
    <Var name="$names" id="5" promote="true" type="item()*"/>
    <Var name="$active" id="6" promote="true" type="item()*"/>
    <Var name="$event" id="7" promote="true" type="item()*"/>
    <GFLWOR type="item()*">
      <Let type="xs:string" size="1" name="$do" id="8">
        <FnSubstring name="substring" type="xs:string" size="1">
          <VarRef type="xs:string*" name="$event" id="7" promote="true"/>
          <Int type="xs:integer" size="1">1</Int>
          <Int type="xs:integer" size="1">1</Int>
        </FnSubstring>
      </Let>
      <Where type="xs:boolean" size="1">
        <FnNormalizeSpace name="normalize-space" type="xs:string" size="1">
          <VarRef type="xs:string" size="1" name="$do" id="8"/>
        </FnNormalizeSpace>
      </Where>
      <If type="item()+">
        <CmpSimpleG op="=" type="xs:boolean" size="1">
          <VarRef type="xs:string" size="1" name="$do" id="8"/>
          <Str type="xs:string" size="1">{</Str>
        </CmpSimpleG>
        <List type="item()+">
          <FnConcat name="concat" type="xs:string" size="1">
            <Str type="xs:string" size="1">&lt;</Str>
            <FnHead name="head" type="xs:string?">
              <VarRef type="xs:string*" name="$names" id="5" promote="true"/>
            </FnHead>
            <Str type="xs:string" size="1">&gt;</Str>
          </FnConcat>
          <StaticFuncCall name="reuse:tag" tailCall="false" type="item()*">
            <FnTail name="tail" type="xs:string*">
              <VarRef type="xs:string*" name="$names" id="5" promote="true"/>
            </FnTail>
            <List type="xs:string*">
              <FnHead name="head" type="xs:string?">
                <VarRef type="xs:string*" name="$names" id="5" promote="true"/>
              </FnHead>
              <VarRef type="xs:string*" name="$active" id="6" promote="true"/>
            </List>
            <FnSubstring name="substring" type="xs:string" size="1">
              <VarRef type="xs:string*" name="$event" id="7" promote="true"/>
              <Int type="xs:integer" size="1">2</Int>
            </FnSubstring>
          </StaticFuncCall>
        </List>
        <List type="item()+">
          <FnConcat name="concat" type="xs:string" size="1">
            <Str type="xs:string" size="1">&lt;/</Str>
            <FnHead name="head" type="xs:string?">
              <VarRef type="xs:string*" name="$active" id="6" promote="true"/>
            </FnHead>
            <Str type="xs:string" size="1">&gt;</Str>
          </FnConcat>
          <StaticFuncCall name="reuse:tag" tailCall="false" type="item()*">
            <VarRef type="xs:string*" name="$names" id="5" promote="true"/>
            <FnTail name="tail" type="xs:string*">
              <VarRef type="xs:string*" name="$active" id="6" promote="true"/>
            </FnTail>
            <FnSubstring name="substring" type="xs:string" size="1">
              <VarRef type="xs:string*" name="$event" id="7" promote="true"/>
              <Int type="xs:integer" size="1">2</Int>
            </FnSubstring>
          </StaticFuncCall>
        </List>
      </If>
    </GFLWOR>
  </StaticFunc>
  <GFLWOR type="element(structure-patterns)" size="1">
    <Let type="(map(xs:string, xs:string+))*" name="$rawPatterns" id="20" 
as="(map(xs:string, xs:string+))+">
      <GFLWOR type="(map(xs:string, xs:string+))*">
        <For type="element()" size="1" name="$list" id="21">
          <CachedPath type="element()*" database="data">
            <TypeCheck as="document-node()+" type="document-node()+" 
database="data">
              <IterPath type="document-node()*" database="data">
                <DBNodeSeq type="document-node()+" size="15432" database="data">
                  <DBNode pre="0" type="document-node()" size="1" 
database="data"/>
                  <DBNode pre="101" type="document-node()" size="1" 
database="data"/>
                  <DBNode pre="345" type="document-node()" size="1" 
database="data"/>
                  <DBNode pre="440" type="document-node()" size="1" 
database="data"/>
                  <DBNode pre="497" type="document-node()" size="1" 
database="data"/>
                </DBNodeSeq>
                <IterStep axis="self" test="node()" type="document-node()?">
                  <FnEndsWith name="ends-with" type="xs:boolean" size="1">
                    <FnDocumentUri name="document-uri" type="xs:anyURI?"/>
                    <Str type="xs:string" size="1">.xml</Str>
                  </FnEndsWith>
                </IterStep>
              </IterPath>
            </TypeCheck>
            <IterStep axis="descendant" test="*" type="element()*">
              <CmpHashG op="=" type="xs:boolean" size="1">
                <FnName name="name" type="xs:string" size="1"/>
                <StrSeq type="xs:string+" size="6">
                  <Str type="xs:string" size="1">block</Str>
                  <Str type="xs:string" size="1">defblock</Str>
                  <Str type="xs:string" size="1">fnblock</Str>
                  <Str type="xs:string" size="1">primaryblock</Str>
                  <Str type="xs:string" size="1">regblock</Str>
                </StrSeq>
              </CmpHashG>
            </IterStep>
          </CachedPath>
        </For>
        <Let type="xs:string" size="1" name="$pattern" id="22">
          <StaticFuncCall name="reuse:getStruct" tailCall="false" 
type="xs:string" size="1">
            <VarRef type="element()" size="1" database="data" name="$list" 
id="21"/>
          </StaticFuncCall>
        </Let>
        <GroupBy type="xs:string" size="1">
          <GroupSpec type="xs:string" size="1" name="$pattern" id="23">
            <VarRef type="xs:string" size="1" name="$pattern" id="22"/>
          </GroupSpec>
        </GroupBy>
        <MapEntry name="map:entry" type="map(xs:string, xs:string+)" size="1">
          <VarRef type="xs:string" size="1" name="$pattern" id="23"/>
          <DualMap type="xs:string+">
            <VarRef type="element()+" name="$list" id="24"/>
            <FnConcat name="concat" type="xs:string" size="1">
              <FnBaseUri name="base-uri" type="xs:anyURI?">
                <ContextValue type="element()" size="1"/>
              </FnBaseUri>
              <FnReplace name="replace" type="xs:string" size="1">
                <FnPath name="path" type="xs:string" size="1">
                  <ContextValue type="element()" size="1"/>
                </FnPath>
                <Str type="xs:string" size="1">Q\{\}</Str>
                <Str type="xs:string" size="1"/>
              </FnReplace>
            </FnConcat>
          </DualMap>
        </MapEntry>
      </GFLWOR>
    </Let>
    <Let type="map(xs:string, xs:string)" size="1" name="$type2patternMap" 
id="25">
      <MapMerge name="map:merge" type="map(xs:string, xs:string)" size="1">
        <GFLWOR type="(map(xs:string, xs:string))*">
          <For type="xs:string" size="1" name="$pattern" id="26">
            <At name="$index" id="27" type="xs:integer" size="1"/>
            <IterMap type="xs:string*">
              <VarRef type="(map(xs:string, xs:string+))+" name="$rawPatterns" 
id="20" as="(map(xs:string, xs:string+))+"/>
              <MapKeys name="map:keys" type="xs:string*">
                <ContextValue type="map(xs:string, xs:string+)" size="1"/>
              </MapKeys>
            </IterMap>
          </For>
          <OrderBy type="item()*">
            <OrderKey dir="ascending" empty="least" type="item()*">
              <VarRef type="xs:string" size="1" name="$pattern" id="26"/>
            </OrderKey>
          </OrderBy>
          <MapEntry name="map:entry" type="map(xs:string, xs:string)" size="1">
            <FnConcat name="concat" type="xs:string" size="1">
              <Str type="xs:string" size="1">type</Str>
              <VarRef type="xs:integer" size="1" name="$index" id="27"/>
            </FnConcat>
            <VarRef type="xs:string" size="1" name="$pattern" id="26"/>
          </MapEntry>
        </GFLWOR>
      </MapMerge>
    </Let>
    <Let type="map(xs:string, xs:anyAtomicType)" size="1" 
name="$pattern2typeMap" id="28" as="map(xs:string, xs:string)">
      <MapMerge name="map:merge" type="map(xs:string, xs:anyAtomicType)" 
size="1">
        <DualMap type="(map(xs:string, xs:anyAtomicType))*">
          <MapKeys name="map:keys" type="xs:string*">
            <VarRef type="map(xs:string, xs:string)" size="1" 
name="$type2patternMap" id="25"/>
          </MapKeys>
          <MapEntry name="map:entry" type="map(xs:string, xs:anyAtomicType)" 
size="1">
            <DynFuncCall tailCall="false" type="xs:string?">
              <ContextValue type="xs:anyAtomicType" size="1"/>
              <VarRef type="map(xs:string, xs:string)" size="1" 
name="$type2patternMap" id="25"/>
            </DynFuncCall>
            <ContextValue type="xs:anyAtomicType" size="1"/>
          </MapEntry>
        </DualMap>
      </MapMerge>
    </Let>
    <ItemMap type="element(structure-patterns)" size="1">
      <TypeCheck as="map(xs:string, xs:string+)" type="map(xs:string, 
xs:string+)" size="1">
        <MapMerge name="map:merge" type="map(xs:string, xs:string*)" size="1">
          <DualMap type="(map(xs:string, xs:string*))+">
            <VarRef type="(map(xs:string, xs:string+))+" name="$rawPatterns" 
id="20" as="(map(xs:string, xs:string+))+"/>
            <MapEntry name="map:entry" type="map(xs:string, xs:string*)" 
size="1">
              <DynFuncCall tailCall="false" type="xs:string?">
                <MapKeys name="map:keys" type="xs:string*">
                  <ContextValue type="map(xs:string, xs:string+)" size="1"/>
                </MapKeys>
                <VarRef type="map(xs:string, xs:string)" size="1" 
name="$pattern2typeMap" id="28" as="map(xs:string, xs:string)"/>
              </DynFuncCall>
              <UtilMapValues name="util:map-values" type="xs:string*">
                <ContextValue type="map(xs:string, xs:string+)" size="1"/>
              </UtilMapValues>
            </MapEntry>
          </DualMap>
        </MapMerge>
      </TypeCheck>
      <CElem type="element(structure-patterns)" size="1">
        <QNm type="xs:QName" size="1">structure-patterns</QNm>
        <GFLWOR type="element(pattern)*">
          <For type="xs:string" size="1" name="$sp" id="31">
            <MapKeys name="map:keys" type="xs:string*">
              <ContextValue type="map(xs:string, xs:string+)" size="1"/>
            </MapKeys>
          </For>
          <Let type="xs:string*" name="$locations" id="32" as="xs:string+">
            <DynFuncCall tailCall="false" type="xs:string*">
              <VarRef type="xs:string" size="1" name="$sp" id="31"/>
              <ContextValue type="map(xs:string, xs:string+)" size="1"/>
            </DynFuncCall>
          </Let>
          <Let type="xs:integer" size="1" name="$found" id="33">
            <FnCount name="count" type="xs:integer" size="1">
              <VarRef type="xs:string+" name="$locations" id="32" 
as="xs:string+"/>
            </FnCount>
          </Let>
          <OrderBy type="item()*">
            <OrderKey dir="descending" empty="least" type="item()*">
              <VarRef type="xs:integer" size="1" name="$found" id="33"/>
            </OrderKey>
          </OrderBy>
          <CElem type="element(pattern)" size="1">
            <QNm type="xs:QName" size="1">pattern</QNm>
            <CAttr type="attribute(number-found)" size="1">
              <QNm type="xs:QName" size="1">number-found</QNm>
              <VarRef type="xs:integer" size="1" name="$found" id="33"/>
            </CAttr>
            <CElem type="element(designation)" size="1">
              <QNm type="xs:QName" size="1">designation</QNm>
              <VarRef type="xs:string" size="1" name="$sp" id="31"/>
            </CElem>
            <CElem type="element(pattern)" size="1">
              <QNm type="xs:QName" size="1">pattern</QNm>
              <ItemMap type="xs:string" size="1">
                <TypeCheck as="element(fn:analyze-string-result)" 
type="element(fn:analyze-string-result)" size="1">
                  <FnAnalyzeString name="analyze-string" type="element()" 
size="1">
                    <TypeCheck as="xs:string" type="xs:string" size="1" 
promote="true">
                      <DynFuncCall tailCall="false" type="xs:string?">
                        <VarRef type="xs:string" size="1" name="$sp" id="31"/>
                        <VarRef type="map(xs:string, xs:string)" size="1" 
name="$type2patternMap" id="25"/>
                      </DynFuncCall>
                    </TypeCheck>
                    <Str type="xs:string" size="1">[\p{L}\p{Nd}._\-:]+</Str>
                  </FnAnalyzeString>
                </TypeCheck>
                <FnStringJoin name="string-join" type="xs:string" size="1">
                  <StaticFuncCall name="reuse:tag" tailCall="false" 
type="item()*">
                    <TypeCheck as="xs:string+" type="xs:string+">
                      <DualMap type="xs:string*">
                        <SingleIterPath type="element(fn:match)*">
                          <IterStep axis="child" test="fn:match" 
type="element(fn:match)*"/>
                        </SingleIterPath>
                        <FnString name="string" type="xs:string" size="1"/>
                      </DualMap>
                    </TypeCheck>
                    <Empty type="empty-sequence()" size="0"/>
                    <FnStringJoin name="string-join" type="xs:string" size="1">
                      <SingleIterPath type="element(fn:non-match)*">
                        <IterStep axis="child" test="fn:non-match" 
type="element(fn:non-match)*"/>
                      </SingleIterPath>
                    </FnStringJoin>
                  </StaticFuncCall>
                </FnStringJoin>
              </ItemMap>
            </CElem>
            <CElem type="element(locations)" size="1">
              <QNm type="xs:QName" size="1">locations</QNm>
              <DualMap type="element(element-info)+">
                <VarRef type="xs:string+" name="$locations" id="32" 
as="xs:string+"/>
                <CElem type="element(element-info)" size="1">
                  <QNm type="xs:QName" size="1">element-info</QNm>
                  <CElem type="element(name)" size="1">
                    <QNm type="xs:QName" size="1">name</QNm>
                    <FnReplace name="replace" type="xs:string" size="1">
                      <FnReplace name="replace" type="xs:string" size="1">
                        <TypeCheck as="xs:string" type="xs:string" size="1" 
promote="true">
                          <UtilLast name="util:last" type="xs:string?">
                            <FnTokenize name="tokenize" type="xs:string*">
                              <ContextValue type="xs:string" size="1"/>
                              <Str type="xs:string" size="1">/</Str>
                            </FnTokenize>
                          </UtilLast>
                        </TypeCheck>
                        <Str type="xs:string" size="1">Q\{\}</Str>
                        <Str type="xs:string" size="1"/>
                      </FnReplace>
                      <Str type="xs:string" size="1">\[\p{Nd}+\]</Str>
                      <Str type="xs:string" size="1"/>
                    </FnReplace>
                  </CElem>
                  <CElem type="element(location)" size="1">
                    <QNm type="xs:QName" size="1">location</QNm>
                    <FnReplace name="replace" type="xs:string" size="1">
                      <ContextValue type="xs:string" size="1"/>
                      <Str type="xs:string" size="1">Q\{\}</Str>
                      <Str type="xs:string" size="1"/>
                    </FnReplace>
                  </CElem>
                </CElem>
              </DualMap>
            </CElem>
          </CElem>
        </GFLWOR>
      </CElem>
    </ItemMap>
  </GFLWOR>
</QueryPlan>

Reply via email to