我有一个看起来像这样的平面XML文件:
<Data>
<DataType1>1</DataType1>
<DataType2>2</DataType2>
<DataType3>3</DataType3>
<DataType4>4</DataType4>
<DataType3>3</DataType3>
<DataType4>4</DataType4>
<DataType1>1</DataType1>
<DataType2>2</DataType2>
<DataType3>3</DataType3>
<DataType4>4</DataType4>
</Data>
我希望能够使用Xquery来嵌套它,看起来像这样:
<Data>
<DataType1>1
<DataType2>2
<DataType3>3
<DataType4>4</DataType4>
</DataType3>
</DataType2>
<DataType3>3
<DataType4>4</DataType4>
</DataType3>
</DataType1>
<DataType1>1
<DataType2>2
<DataType3>3
<DataType4>4</DataType4>
</DataType3>
</DataType2>
</DataType1>
</Data>
我基本上想要根据顺序进行嵌套,因此任何“2”都将嵌套在前一个“1”节点下,依此类推。有什么建议吗?
答案 0 :(得分:0)
编写一个递归函数来取消数据。我添加了一个“调试属性”用于测试目的,随意删除它(以及带有匹配注释的行)。
declare function local:unflatten($xs as node()*) {
for $x in $xs
return
let $next := ($x/following-sibling::*[number(text()) <= number($x/text())])[1]
return
element { concat("DataType", $x/text()) } {
attribute id { $x/@id }, (: remove debug output here :)
$x/text(),
" ", (: Print newline character :)
local:unflatten($x/following-sibling::*[
(empty($next) or . << $next)
and
number(text()) = $x/text() + 1
]
)
}
};
let $xml := <Data>
<DataType1 id="1">1</DataType1>
<DataType2 id="2">2</DataType2>
<DataType3 id="3">3</DataType3>
<DataType4 id="4">4</DataType4>
<DataType3 id="5">3</DataType3>
<DataType4 id="6">4</DataType4>
<DataType1 id="7">1</DataType1>
<DataType2 id="8">2</DataType2>
<DataType3 id="9">3</DataType3>
<DataType4 id="10">4</DataType4>
</Data>
return element Data { local:unflatten($xml/*[text()=1]) }
答案 1 :(得分:0)
我假设示例输出中第一个DataType2元素的结束标记的位置是一个拼写错误,并且在以下DataType3之后它应该实际发生。
以下适用于eXist-db
xquery version "1.0";
declare function local:getLevel($n) as xs:integer {
xs:integer(substring-after($n/local-name(), 'DataType'))
};
declare function local:buildHierarchy($seq) {
if (empty($seq)) then ()
else
let $lvl := local:getLevel($seq[1]),
$until := (
for $el at $p in $seq
where $p gt 1 and local:getLevel($el) le $lvl
return $p
,
count($seq) + 1
)[1]
return (
element { node-name($seq[1]) } {
$seq[1]/text(),
local:buildHierarchy(subsequence($seq, 2, $until - 2))
},
local:buildHierarchy(subsequence($seq, $until))
)
};
let $data := <Data>
<DataType1>1</DataType1>
<DataType2>2</DataType2>
<DataType3>3</DataType3>
<DataType4>4</DataType4>
<DataType3>3</DataType3>
<DataType4>4</DataType4>
<DataType1>1</DataType1>
<DataType2>2</DataType2>
<DataType3>3</DataType3>
<DataType4>4</DataType4>
</Data>
return
<Data>{local:buildHierarchy($data/*)}</Data>
local:getLevel()
确定元素的嵌套优先级(在这种情况下,只需返回元素名称中的数字)。嵌套优先级高于其前一个兄弟的元素将嵌套在其中。
local:buildHierarchy()
完成了构建新结构的真正工作。它基本上将其输入序列分为三部分:(1)第一项,(2)具有较高嵌套优先级的所有连续后续项,以及(3)第一个相等或较低优先级项以及所有后续项。它复制了(1)并在该副本中使用递归嵌套(2),然后在(3)上递归以创建下一个同级别的兄弟。