我有一个XML变量,例如
DECLARE @xml XML =
'<A>
<AA>aa</AA>
<AB>
<ABA>aba</ABA>
</AB>
</A>
<B>b</B>
<C>
<CA>ca</CA>
</C>
我想用一个VARCHAR kolumn获取这个XML表的结构:
structure (VARCHAR)
--------------------
'A/AA'
'A/AB/ABA'
'B'
'C/CA'.
我不需要在节点中获取文本 - 我只需要结构。 XML变量可以不同(我不知道节点数,节点名称等)。
变量@xml可以没有ROOT元素。
我尝试了很多.value()或.nodes()的组合,但它没有用。 最好的结果给我一个操作:
SELECT
grandparent.gname.value('fn:local-name(.)', 'VARCHAR(MAX)'),
parent.pname.value('fn:local-name(.)', 'VARCHAR(MAX)'),
child.cname.value('fn:local-name(.)', 'VARCHAR(MAX)')
FROM
@xml.nodes('*') AS grandparent(gname)
CROSS APPLY
grandparent.gname.nodes('*') AS parent(pname)
CROSS APPLY
parent.pname.nodes('*') AS child(cname)
它给了我A / AB / ABA&#39;但如果我不知道节点和节点名称的数量,那么我继续是没用的。
答案 0 :(得分:2)
使用递归CTE一次提取一级节点。锚点部分提取根节点,query('*')
获取找到的每个节点的子节点。 exist('*')
用于过滤掉递归期间创建的中间行。递归部分与锚点相同,只是它使用SubNodes
中提供的XML。
declare @xml xml =
'<A>
<AA>aa</AA>
<AB>
<ABA>aba</ABA>
</AB>
</A>
<B>b</B>
<C>
<CA>ca</CA>
</C>';
with C as
(
select T.X.value('local-name(.)', 'nvarchar(max)') as Structure,
T.X.query('*') as SubNodes,
T.X.exist('*') as HasSubNodes
from @xml.nodes('*') as T(X)
union all
select C.structure + N'/' + T.X.value('local-name(.)', 'nvarchar(max)'),
T.X.query('*'),
T.X.exist('*')
from C
cross apply C.SubNodes.nodes('*') as T(X)
)
select C.Structure
from C
where C.HasSubNodes = 0;
结果:
Structure
---------
B
C/CA
A/AA
A/AB/ABA