xml - 将元素序列转换为树

标签 xml xquery flwor tei

我有一个元素列表,其中包含有关它们在 XML 树中的位置信息。 “底部”的元素,即出现在深度较低的元素之前的那些元素,包含文本。

<input>
    <text n="x" xml:id="a" depth="1"/>
    <div xml:id="b" depth="2"/>
    <div xml:id="c" depth="3"/>
    <p xml:id="e" depth="4">text</p>
    <p xml:id="d" depth="4">text</p>
    <p xml:id="x" depth="4">text</p>
    <div xml:id="f" depth="3"/>
    <lg xml:id="j" depth="4"/>
    <l xml:id="k" depth="5">text</l>
    <l xml:id="l" depth="5">text</l>
    <p xml:id="n" depth="3">text</p>
</input>

我想在一次操作中将其重构为下面的 XML 树。

<text n="x" xml:id="a" depth="1">
    <div xml:id="b" depth="2">
        <div xml:id="c" depth="3">
            <p xml:id="e" depth="4">text</p>
            <p xml:id="d" depth="4">text</p>
            <p xml:id="x" depth="4">text</p>
        </div>
        <div xml:id="f" depth="3">
            <lg xml:id="j" depth="4">
                <l xml:id="k" depth="5">text</l>
                <l xml:id="l" depth="5">text</l>
            </lg>
        </div>
        <p xml:id="n" depth="3">text</p>
    </div>
</text>

我想我需要从最高深度的元素开始,即深度为 5 的所有元素,然后将它们包裹在深度 5-1 的前一个元素中,依此类推,但我无法得到我在思考如何通过这个进行递归。

@xml:ids 仅供引用。

我的问题与我之前的 stackoverflow 相反题。它类似于这个 stackoverflow问题,但我需要使用 XQuery。

最佳答案

构建一个递归构建树的函数。此代码非常通用,通过更改 local:getLevel($node) 函数,它应该适用于任意“扁平化”树。

declare function local:getLevel($node as element()) as xs:integer {
  $node/@depth
};

declare function local:buildTree($nodes as element()*) as element()* {
  let $level := local:getLevel($nodes[1])
  (: Process all nodes of current level :)
  for $node in $nodes
  where $level eq local:getLevel($node)

  (: Find next node of current level, if available :)
  let $next := ($node/following-sibling::*[local:getLevel(.) le $level])[1]
  (: All nodes between the current node and the next node on same level are children :)
  let $children := $node/following-sibling::*[$node << . and (not($next) or . << $next)]

  return
    element { name($node) } {
      (: Copy node attributes :)
      $node/@*,
      (: Copy all other subnodes, including text, pi, elements, comments :)
      $node/node(),

      (: If there are children, recursively build the subtree :)
      if ($children)
      then local:buildTree($children)
      else ()
    }
};

let $xml := document {
  <input>
    <text n="x" xml:id="a" depth="1"/>
    <div xml:id="b" depth="2"/>
    <div xml:id="c" depth="3"/>
    <p xml:id="e" depth="4">text</p>
    <p xml:id="d" depth="4">text</p>
    <p xml:id="x" depth="4">text</p>
    <div xml:id="f" depth="3"/>
    <lg xml:id="j" depth="4"/>
    <l xml:id="k" depth="5">text</l>
    <l xml:id="l" depth="5">text</l>
    <p xml:id="n" depth="3">text</p>
  </input>
}

return local:buildTree($xml/input/*)

我特此将此代码发布到公共(public)领域。

如果您的 XQuery 处理器不支持增强的 FLWOR 表达式,您需要重新排序某些行;我省略了评论:

  for $node in $nodes
  let $level := local:getLevel($nodes[1])
  let $next := ($node/following-sibling::*[local:getLevel(.) le $level])[1]
  let $children := $node/following-sibling::*[$node << . and (not($next) or . << $next)]
  where $level eq local:getLevel($node)

关于xml - 将元素序列转换为树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21527660/

相关文章:

android - 无法将颜色转换为可绘制对象

android - 膨胀异常 : Binary XML file line #19: Error inflating class EditText

xml - 如何将一个 FLWOR 通过管道传输到另一个 FLWOR 中?

xquery-获取单个父元素中不为空的元素的计数

xml - 在 MLCP 中作为 -query_filter 传递时无效值运算符 '<'(小于)符号

xml - XQuery 中的通配符对应于 SQL 中的 [where LIKE '%.mp3' ]

java - 如何在spring jpa中使用to转换器

xml - Spring xml配置启用@Async而不启用@Scheduled

Marklogic 使用 cts 计数旧文档 :search over FLWOR

xml - FLWOR XQuery 仅返回唯一单词组合,以及组合出现的次数,按频率降序排序