2014-03-06 53 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行,所以我很难指望无论如何,以毫秒为单位完成函数! –

相关问题