调用函数来处理自己的结果一定次数

时间:2014-03-06 21:35:32

标签: xquery tei

我有一个查询,它附加了@xml:ids中元素的唯一引用。它应该工作,但我怎么能避免函数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:ids才能获得它们自己(顶层必须用@xml:id播种)。

1 个答案:

答案 0 :(得分: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)