【问题标题】:Transforming flat xml to nested xml using Xquery and recursive functions使用 Xquery 和递归函数将平面 xml 转换为嵌套 xml
【发布时间】:2012-07-10 15:15:31
【问题描述】:

我对在 Xquery 中进行递归函数的练习感到困扰。我需要仅使用 Xquery 将平面 XML 树转换为嵌套 XML 树。

平面 XML 如下所示:

    <?xml version="1.0"?>
    <tree>
      <node id="1" type="Folder">
        <child>2</child>
        <child>3</child>
      </node>
      <node id="2" type="Folder">
        <child>4</child>
      </node>
      <node id="3" type="Folder">
        <child>5</child>
        <child>6</child>
      </node>
      <node id="4" type="Item" />
      <node id="5" type="Folder">
        <child>7</child>
      </node>
      <node id="6" type="Item" />
      <node id="7" type="Item" />
    </tree>

所需的嵌套 XML 如下所示:

    <?xml version="1.0"?>
    <tree>
      <node id="1" type="Folder" children="2 3">
        <node id="2" type="Folder">
          <node id="4" type="Item" />
        </node>
        <node id="3" type="Folder">
          <node id="5" type="Folder" children="7">
            <node id="7" type="Item" />
          </node>
          <node id="6" type="Item" />
        </node>
      </node>
    </tree>

我尝试在没有递归函数的情况下对此进行 Xquery,但运气不佳。尤其是条件反射对我来说似乎很奇怪;新嵌套 XML 的根元素应该是 id="1" 的节点,因为它不作为任何其他元素的子元素存在。但是,如果我尝试将此指定为条件,例如下面,似乎不可能只选择该节点。

    for $node in /Tree/node[@id != /Tree/node/child]
    return
    <node id="{data($node/@id)}" type="{data($node/@type)}">

            (: Lower level subqueries.... :)

    </node>

更新:我已经走得更远了,但现在我在选择具有等于父节点内容的 id 的节点时遇到了 [条件],即递归函数中的 for 语句不返回任何节点,这是意料之外的。

这是我目前的代码:

    declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
    declare namespace local = "localhost";
    declare option output:method "xml";
    declare option output:omit-xml-declaration "no";
    declare option output:indent "yes";
    declare option output:doctype-system "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";

    declare function local:addSubNode($n)
    {
        for $subnode in doc("xml/flat-tree.xml")/tree/node[@id = $n]
            let $subnid:=data($subnode/@id)
            let $subtype:=data($subnode/@type)
        return <node id="{$subnid}" type="{$subtype}">
                {local:addSubNode($subnid)}
                </node>
        };

    <tree>

    {
    for $node in doc("xml/flat-tree.xml")/tree/node[not(@id = /tree/node/child)]
    let $nid:=data($node/@id)

    return <node id="{$nid}" type="{data($node/@type)}"> 
        {for $child in $node
        let $cid:=data($child)
        return local:addSubNode($cid)
        }

            </node>
    }

    </tree>

【问题讨论】:

    标签: xml-serialization xquery


    【解决方案1】:

    只是部分答案 - =!= 可以将原子值与序列进行比较,但它可以作为每个术语的逻辑或。那就是“a = b”的意思是“b中是否有一个等于a的值”,而“a!= b”的意思是“b中是否有一个不等于a的值”,这不是你要找的.您想要“b 中没有等于 a 的值”,即“not(a = b)”。

    for $node in $d/node[not(@id = $d/node/child)] return
    <node id="{$node/@id}" type="{$node/@type}">
        (: etc. :)
    </node>
    

    【讨论】:

    • 感谢您的回复,我会尝试新的限制!
    • 我想我快到了,但无法使递归函数中的 [] 选择起作用。知道我的最新查询可能有什么问题吗?见上文。
    • 是否可以在递归函数中使用 $cid 变量作为 $n?
    【解决方案2】:

    好的,知道了!最终我将整个 $node 或 $child 元素提供给递归函数,而不仅仅是它的 id 属性,现在它可以工作了!

        declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";
        declare namespace local = "localhost";
        declare option output:method "xml";
        declare option output:omit-xml-declaration "no";
        declare option output:indent "yes";
        declare option output:doctype-system "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
    
        (:lookupChildren function :)
        declare function local:lookupChildren($p)
        {
        for $child in $p/child
        return $child
        };
    
        declare function local:addSubNode($n)
        {
        for $subnode in doc("xml/flat-tree.xml")/tree/node
                let $subnid:=data($subnode/@id)
                let $subtype:=data($subnode/@type)
        where $subnode/@id = $n/child
            return 
            <node id="{$subnid}" type="{$subtype}" children="{local:lookupChildren($subnode)}">
                   {local:addSubNode($subnode)}
                    </node>
        };
    
        <tree>
    
        {
        for $node in doc("xml/flat-tree.xml")/tree/node[not(@id = /tree/node/child)]
        let $nid:=data($node/@id)
        let $ntype:=data($node/@type)
    
        return  <node id="{$nid}" type="{$ntype}" children="{local:lookupChildren($node)}"> 
                {local:addSubNode($node)}
    
                </node>
        }
    
        </tree>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-05
      • 2016-07-09
      • 2012-04-04
      相关资源
      最近更新 更多