2014-03-06 26 views
0

我有一個查詢,它附加了@xml:id中元素的唯一引用。它的工作原理應該如何,但我該如何避免函數local的重複:add-references()?調用一個函數來處理自己的結果一定的次數

xquery version "3.0"; 

declare namespace tei="http://www.tei-c.org/ns/1.0"; 

declare function local:change-attributes($node as node(), $new-name as xs:string, $new-content as item(), $action as xs:string, $target-element-names as xs:string+, $target-attribute-names as xs:string+) as node()+ { 
    if ($node instance of element()) 
    then 
     element {node-name($node)} 
     { 
      if ($action = 'attach-attribute-to-element' and name($node) = $target-element-names) 
      then ($node/@*, attribute {$new-name} {$new-content}) 
      else 
      $node/@* 
      , 
      for $child in $node/node() 
      return $child   
     } 
    else $node 
}; 

declare function local:add-references($element as element()) as element() { 
    element {node-name($element)} 
    {$element/@*, 
    for $child in $element/node() 
     return 
      if ($child instance of element() and $child/../@xml:id) 
      then 
       if (not($child/@xml:id)) 
       then 
        let $local-name := local-name($child) 
        let $preceding-siblings := $child/preceding-sibling::element() 
        let $preceding-siblings := count($preceding-siblings[local-name(.) eq $local-name]) 
        let $following-siblings := $child/following-sibling::element() 
        let $following-siblings := count($following-siblings[local-name(.) eq $local-name]) 
        let $seq-no := 
         if ($preceding-siblings = 0 and $following-siblings = 0) 
         then '' 
         else $preceding-siblings + 1 
        let $id-value := concat($child/../@xml:id, '-', $local-name, if ($seq-no) then '-' else '', $seq-no) 
        return 
         local:change-attributes($child, 'xml:id', $id-value, 'attach-attribute-to-element', ('body', 'quote', 'titlePage','text','p','div','front','head','titlePart'), '') 
       else local:add-references($child) 
      else 
       if ($child instance of element()) 
       then local:add-references($child) 
       else $child 
     } 
}; 

let $doc := 
<TEI xmlns="http://www.tei-c.org/ns/1.0"> 
    <text xml:id="hamlet"> 
     <front> 
     <div> 
      <p>…</p> 
     </div> 
     <titlePage> 
      <titlePart>…</titlePart> 
     </titlePage> 
     <div> 
      <p>…</p> 
     </div> 
     </front> 
     <body> 
     <p>…</p> 
     <quote>…</quote> 
     <p>…</p> 
     <div> 
      <head>…</head> 
      <p>…</p> 
      <quote>…</quote> 
      <p>…</p> 
      <p>…</p> 
     </div> 
     <div> 
      <lg> 
       <l>…</l> 
       <l>…</l> 
      </lg> 
     </div> 
     </body> 
    </text> 
</TEI> 

return local:add-references(local:add-references(local:add-references(local:add-references(local:add-references($doc))))) 

必須有某種方式遞歸地調用一個函數,使用文檔的深度將它自身打包一定次數。

問題在於,元素的某個深度必須等到它們的父元素被賦予@xml:id後才能獲得它們自己的(頂級必須使用@xml:id播種)。

+0

你就不能使用更新的值返回元素後進行遞歸調用? 'local:add-references(local:change-attributes($ child,'xml:id',$ id-value,...') – wst

回答

2

這可能不是最好的解決辦法,但你可能只是測試應用該功能仍然改變任何東西,否則取消:

declare function local:add-references-recursively($now as element()) as element() { 
    let $next := local:add-references($now) 
    return 
    if (deep-equal($now, $next)) 
    then $now 
    else local:add-references-recursively($next) 
}; 

並調用使用

local:add-references-recursively($doc) 
+0

是的,現在我明白了:遞歸直到完成爲止,也就是說,你有這段時間和你上次一樣 - 獲取文檔深度是不必要的。再次感謝Jens,讓我看看方式。速度不是問題 - 我的文檔長22,138行,所以我很難指望無論如何,以毫秒爲單位完成函數! –

相關問題