0

我有一个查询,它附加了对@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>…&lt;/p>
         </div>
         <titlePage>
            <titlePart>…&lt;/titlePart>
         </titlePage>
         <div>
            <p>…&lt;/p>
         </div>
      </front>
      <body>
         <p>…&lt;/p>
         <quote>…&lt;/quote>
         <p>…&lt;/p>
         <div>
            <head>…&lt;/head>
            <p>…&lt;/p>
            <quote>…&lt;/quote>
            <p>…&lt;/p>
            <p>…&lt;/p>
         </div>
         <div>
            <lg>
               <l>…&lt;/l>
               <l>…&lt;/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 作为种子)。

4

1 回答 1

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)
于 2014-03-06T21:59:37.203 回答