从大文件中获取不同的XML节点列表
我试图从XML文件中获取一个不同的节点名称列表。我成功地使用了类似于的递归CTE,但只使用了少于大约1m个字符的文件。除此之外,查询似乎永远不会返回。我的一些文件大约有100个字符 从那以后,我开始尝试PowerShell。对于此示例XML:从大文件中获取不同的XML节点列表,xml,powershell,sql-server-2008,Xml,Powershell,Sql Server 2008,我试图从XML文件中获取一个不同的节点名称列表。我成功地使用了类似于的递归CTE,但只使用了少于大约1m个字符的文件。除此之外,查询似乎永远不会返回。我的一些文件大约有100个字符 从那以后,我开始尝试PowerShell。对于此示例XML: <?xml version="1.0" encoding="UTF_8"?> <root> <childA> <descendant1> <descendant1_1>
<?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>
这给了我:
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
下面是一个简单的解决方案,假设您知道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}
}
还添加了SQLXQuery版本。它仍然需要对结构的了解,并且一次只执行一个级别,但它没有交叉应用/连接,因此可能在大型文件上工作得更好
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)
如果我们讨论的是这个问题的硬编码解决方案,那么下面是我使用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);
SQL server上是否有存储这些xml值的表?是否需要添加一个
交叉应用
,以取消对结果的IVOT,但这满足了我的需要。我仍然不确定为什么这种方法比我开始使用的CTE快得多,但对于这个应用程序中的动态递归来说,这是一个很好的交换。
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 | | |
+------+--------+-------------+---------------+-----------------+