2017-06-19 69 views
1

我想弄清楚如何處理XML重複結構。在下面的例子中,史密斯先生應該有兩個孩子(麥克和湯姆),瑪格女士應該沒有孩子。湯姆,史密斯先生的孩子有一個名叫莎莉的孩子,他是史密斯先生的孫子。 Magoo女士沒有子女,也沒有孫子女。用重複結構解析XML

DECLARE @tableXML table (
ID int NOT NULL, 
XMLdata xml NOT NULL 
); 

DECLARE @testXML xml 
SET @testXML = 
'<parent> 
    <name>Mr. Smith</name> 
    <child> 
     <name>Mike</name> 
     <child /> 
    </child> 
    <child> 
     <name>Tom</name> 
     <child> 
      <name>Sally</name> 
     </child> 
    </child> 
</parent> 
<parent> 
    <name>Ms. Magoo</name> 
    <child> 
     <name /> 
     <child /> 
    </child> 
</parent>' 

INSERT INTO @tableXML VALUES 
(1, @testXML); 

SELECT 
    IsNull(parent.p.value('self::node()','varchar(100)'),Null) AS [Parent], 
    IsNull(children.c.value('self::node()','varchar(100)'),Null) AS [Child], 
    IsNull(grandChildren.g.value('self::node()','varchar(100)'),Null) AS [Grandchild] 
FROM @tableXML 
CROSS APPLY XMLdata.nodes('/parent/name') AS parent (p) 
CROSS APPLY parent.p.nodes('/parent/child/name') AS children (c) 
CROSS APPLY children.c.nodes('/parent/child/child/name') AS grandChildren (g) 

的結果集的上面是:

Parent | Child | Grandchild 
--------------------------------- 
Mr. Smith Mike  Sally 
Mr. Smith Tom  Sally 
Mr. Smith    Sally 
Ms. Magoo Mike  Sally 
Ms. Magoo Tom  Sally 
Ms. Magoo    Sally 

結果應該是:

Parent | Child | Grandchild 
--------------------------------- 
Mr. Smith Mike  
Mr. Smith Tom  Sally 
Ms. Magoo  

的思考?

謝謝! 邁克

+0

大,那你提供了一些* copy'n'paste *測試代碼! +1從我身邊 – Shnugo

+0

這是有限的深度(在這種情況下:3級),或者你在尋找一種通用的方法(可能莎莉也有孩子)? – Shnugo

+0

Btw:怎麼樣'IsNull()'?如果它是'NULL',則返回'NULL'? – Shnugo

回答

0

試試這樣:

SELECT 
    p2.lin.value('(./name)[1]','varchar(100)') AS [Parent], 
    p3.lin.value('self::node()','varchar(100)') AS [Child], 
    p3.lin.value('(./child)[1]','varchar(100)') AS [GrandChild] 
FROM @tableXML 
CROSS APPLY XMLdata.nodes('/parent') AS p2(lin) 
CROSS APPLY p2.lin.nodes('child') AS p3(lin) 
GO 
 
Parent | Child | GrandChild 
:-------- | :------- | :--------- 
Mr. Smith | Mike  |   
Mr. Smith | TomSally | Sally  
Ms. Magoo |   |   

dbfiddle here

+0

如果莎莉有一個兄弟(比「湯姆」低一個孩子),你會在所有情況下閱讀第一個。你錯過了第三級的'.nodes()'... – Shnugo

0

你是關閉...

隨着CROSS APPLY xyz.nodes()你CA越來越深入嵌套結構。但是您必須將其想像爲您的樹中的相對地址(當前位置)。

有了這樣

CROSS APPLY parent.p.nodes('/parent/child/name') AS children (c) 

...你正在閱讀從根右下來了,不是開始parent.p

試試這樣一行:

SELECT 
    IsNull(parent.p.value('(name/text())[1]','varchar(100)'),Null) AS [Parent], 
    IsNull(children.c.value('(name/text())[1]','varchar(100)'),Null) AS [Child], 
    IsNull(grandChildren.g.value('(name/text())[1]','varchar(100)'),Null) AS [Grandchild] 
FROM @tableXML 
CROSS APPLY XMLdata.nodes('/parent') AS parent (p) 
CROSS APPLY parent.p.nodes('child') AS children (c) 
CROSS APPLY children.c.nodes('child') AS grandChildren (g);