我正在尝试从XML文件中获得不同的节点名称列表。我成功使用了类似于https://stackoverflow.com/a/2274091/1735928的递归CTE,但仅使用了小于1m个字符的文件。在此之上,查询似乎永远不会返回。我的一些文件大约在1亿个字符左右。
此后,我开始尝试使用PowerShell。对于此样本XML:
<?xml version="1.0" encoding="UTF_8"?>
<root>
<childA>
<descendant1>
<descendant1_1>
<descendant1_1_1>1111111111</descendant1_1_1>
</descendant1_1>
</descendant1>
<descendant2>0</descendant2>
</childA>
<childA>
<descendant1>
<descendant1_1>
<descendant1_1_1>2222222222</descendant1_1_1>
</descendant1_1>
</descendant1>
<descendant2>2</descendant2>
</childA>
<childB>
<descendant1>
<descendant1_1>
<descendant1_1_1>2222222222</descendant1_1_1>
</descendant1_1>
</descendant1>
<descendant3>0</descendant3>
</childB>
<childC>
<descendant4>0</descendant4>
</childC>
<childC>
<descendant4>6</descendant4>
</childC>
</root>
我已经做到了:
$xml.childnodes[1].childnodes | select -uniq | foreach { $xml.childnodes[1].($_.name).childnodes.name | select -uniq }
这给了我
descendant1
descendant2
descendant1
descendant3
descendant4
但是不包括其他后代。最终,我试图将表恢复为如下所示的SQL:
root | childA | descendant1
root | childA | descendant1_1
root | childA | descendant1_1_1
root | childA | descendant2
root | childB | descendant1
root | childB | descendant1_1
root | childB | descendant1_1_1
root | childB | descendant3
root | childC | descendant4
答案 0 :(得分:1)
下面是一个幼稚的解决方案,假设您知道xml的深度。 但是可能您可以使用xqury进行全部操作,从而在SQL端完成
[xml]$x = "your xml here"
# ------ LEVEL 2 children
$L2 = $x | Select-Xml "//root/*/*"
foreach($n in $L2) {
$L1 = $n.node.ParentNode.LocalName
$CHILD = $n.node.localname
[PSCustomObject]@{L1=$L1; CHILD = $CHILD}
}
# ------ LEVEL 3 children
$L3 = $x | Select-Xml "//root/*/*/*"
foreach($n in $L3) {
$L1 = $n.node.ParentNode.ParentNode.LocalName
$CHILD = $n.node.localname
[PSCustomObject]@{L1=$L1; CHILD = $CHILD}
}
# ------ LEVEL 4 children
$L4 = $x | Select-Xml "//root/*/*/*/*"
foreach($n in $L4) {
$L1 = $n.node.ParentNode.ParentNode.ParentNode.LocalName
$CHILD = $n.node.localname
[PSCustomObject]@{L1=$L1; CHILD = $CHILD}
}
还添加了SQL xquery版本。它仍然需要了解结构,并且一次只能执行一个级别,但是它没有交叉应用/联接,因此可能会在大型文件上更好地工作
select
T.c.query('local-name(.)') as self
,T.c.query('local-name(..)') as parent
,T.c.query('local-name(../..)') as Gparent
,T.c.query('local-name(../../..)') as GGparent
from @x.nodes('/root/*/*/*/*') T(c)
答案 1 :(得分:1)
如果我们正在谈论针对此问题的硬编码解决方案,那么这是我使用SQL Server的解决方案。
DECLARE @x XML = '
<root>
<childA>
<descendant1>
<descendant1_1>
<descendant1_1_1>1111111111</descendant1_1_1>
</descendant1_1>
</descendant1>
<descendant2>0</descendant2>
</childA>
<childA>
<descendant1>
<descendant1_1>
<descendant1_1_1>2222222222</descendant1_1_1>
</descendant1_1>
</descendant1>
<descendant2>2</descendant2>
</childA>
<childB>
<descendant1>
<descendant1_1>
<descendant1_1_1>2222222222</descendant1_1_1>
</descendant1_1>
</descendant1>
<descendant3>0</descendant3>
</childB>
<childC>
<descendant4>0</descendant4>
</childC>
<childC>
<descendant4>6</descendant4>
</childC>
</root>
';
SELECT
x.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') root,
L2.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L2,
L3.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L3,
L4.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L4,
L5.n.value('fn:local-name(.)', 'NVARCHAR(MAX)') L5
FROM @x.nodes('/*') x(n)
OUTER APPLY x.n.nodes('*') L2(n)
OUTER APPLY L2.n.nodes('*') L3(n)
OUTER APPLY L3.n.nodes('*') L4(n)
OUTER APPLY L4.n.nodes('*') L5(n);
输出
+------+--------+-------------+---------------+-----------------+
| root | L2 | L3 | L4 | L5 |
+------+--------+-------------+---------------+-----------------+
| root | childA | descendant1 | descendant1_1 | descendant1_1_1 |
| root | childA | descendant2 | | |
| root | childA | descendant1 | descendant1_1 | descendant1_1_1 |
| root | childA | descendant2 | | |
| root | childB | descendant1 | descendant1_1 | descendant1_1_1 |
| root | childB | descendant3 | | |
| root | childC | descendant4 | | |
| root | childC | descendant4 | | |
+------+--------+-------------+---------------+-----------------+