如何解决如何通过值获取XML中的节点路径?
我具有具有多个节点结构的XML,并希望通过使用SQL Server 2012搜索值“ 12345”来获取XML中的节点路径。
示例XML:
<?xml version="1.0" encoding="UTF-8"?>
<Parent>
<DataExtensions>
<DataItem key="Key1" type="String">
<value>12345</value>
</DataItem>
<DataItem key="Key2" type="String">
<value>6789</value>
</DataItem>
</DataExtensions>
<TestKey1>12345</TestKey1>
<Answers>
<AnswersList>
<Entry key="Key2" type="Answer">
<value ID="Key1ID" Text="12345" />
</Entry>
<Entry key="Key3" type="Answer">
<value ID="Key3ID" Text="6789" />
</Entry>
</AnswersList>
</Answers>
<TestKey2>12345</TestKey2>
<TestKey3>67890</TestKey3>
<TestKey4>12345</TestKey3>
</Parent>
我能够通过为每个select语句编写来获取值,但我想获取整个XML中键值或值等于12345的节点路径。
表中所需的输出为:
(/*/TestKey1/text())
(/*/TestKey2/text())
(/*/TestKey4/text())
(/*/DataExtensions/DataItem[@key=("Key1")]/value())
(/*/Answers/AnswersList/Entry[@key=("Key2")]/value/text())
请帮助。
解决方法
您可以尝试以下解决方案。它执行许多强大的功能,包括XML可视树表示。您的答案在输出的[XPath]列中。
T-SQL
DECLARE @xml XML =
N'<Parent>
<DataExtensions>
<DataItem key="Key1" type="String">
<value>12345</value>
</DataItem>
<DataItem key="Key2" type="String">
<value>6789</value>
</DataItem>
</DataExtensions>
<TestKey1>12345</TestKey1>
<Answers>
<AnswersList>
<Entry key="Key2" type="Answer">
<value ID="Key1ID" Text="6789"/>
</Entry>
<Entry key="Key3" type="Answer">
<value ID="Key3ID" Text="12345"/>
</Entry>
</AnswersList>
</Answers>
<TestKey2>12345</TestKey2>
<TestKey3>67890</TestKey3>
<TestKey4>12345</TestKey4>
</Parent>';
-- Solution # 2.
-- a thing of beauty.
WITH cte AS (
SELECT 1 AS lvl,x.value('local-name(.)','NVARCHAR(MAX)') AS Name,CAST(NULL AS NVARCHAR(MAX)) AS ParentName,CAST(1 AS INT) AS ParentPosition,CAST(N'Element' AS NVARCHAR(20)) AS NodeType,'/' + x.value('local-name(.)','NVARCHAR(MAX)') AS FullPath,'NVARCHAR(MAX)')
+ N'['
+ CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NVARCHAR)
+ N']' AS XPath,ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS Position,'NVARCHAR(MAX)') AS Tree,x.value('text()[1]','NVARCHAR(MAX)') AS Value,x.query('.') AS this,x.query('*') AS t,CAST(CAST(1 AS VARBINARY(4)) AS VARBINARY(MAX)) AS Sort,CAST(1 AS INT) AS ID
FROM @xml.nodes('/*') a(x)
UNION ALL
SELECT p.lvl + 1 AS lvl,c.value('local-name(.)',CAST(p.Name AS NVARCHAR(MAX)) AS ParentName,CAST(p.Position AS INT) AS ParentPosition,CAST(p.FullPath + N'/' + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS FullPath,CAST(p.XPath + N'/'+ c.value('local-name(.)','NVARCHAR(MAX)')
+ N'['
+ CAST(ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)') ORDER BY (SELECT 1)) AS NVARCHAR)
+ N']' AS NVARCHAR(MAX)) AS XPath,ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)')
ORDER BY (SELECT 1)) AS Position,CAST( SPACE(2 * p.lvl - 1) + N'|' + REPLICATE(N'-',1) + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS Tree,CAST( c.value('text()[1]','NVARCHAR(MAX)') AS NVARCHAR(MAX) ) AS Value,c.query('.') AS this,c.query('*') AS t,CAST(p.Sort + CAST( (lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS VARBINARY(4)) AS VARBINARY(MAX) ) AS Sort,CAST((lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS INT)
FROM cte p
CROSS APPLY p.t.nodes('*') b(c)),cte2 AS (
SELECT lvl AS Depth,Name AS NodeName,ParentName,ParentPosition,NodeType,FullPath,XPath,Position,Tree AS TreeView,Value,this AS XMLData,Sort,ID
FROM cte
UNION ALL
SELECT p.lvl,'NVARCHAR(MAX)'),p.Name,p.Position,CAST(N'Attribute' AS NVARCHAR(20)),p.FullPath + N'/@' + x.value('local-name(.)',p.XPath + N'/@' + x.value('local-name(.)',1,SPACE(2 * p.lvl - 1) + N'|' + REPLICATE('-',1)
+ N'@' + x.value('local-name(.)',x.value('.',NULL,p.Sort,p.ID + 1
FROM cte p
CROSS APPLY this.nodes('/*/@*') a(x)
)
SELECT ROW_NUMBER() OVER(ORDER BY Sort,ID) AS ID,Depth,NodeName,TreeView,XMLData
FROM cte2
WHERE Value = '12345';
T-SQL,简短版本
DECLARE @DocHandle INT;
EXEC sp_xml_preparedocument @DocHandle OUTPUT,@xml;
--SELECT * FROM OPENXML(@DocHandle,'/*');
;WITH rs AS
(
SELECT * FROM OPENXML(@DocHandle,'/*')
),cte AS
(
-- anchor
SELECT id,ParentID
--,nodetype,[text],CAST(id AS VARCHAR(100)) AS [Path],CAST('/' + rs.localname AS VARCHAR(1000))
+ N'['
+ CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NVARCHAR)
+ N']' AS [XPath]
FROM rs
WHERE ParentID IS NULL
UNION ALL
--recursive member
SELECT t.id,t.ParentID
--,nodetype = (SELECT nodetype FROM rs WHERE id = t.ParentID),t.[text],CAST(a.[Path] + ',' + CAST( t.ID AS VARCHAR(100)) AS VARCHAR(100)) AS [Path],CAST(a.[XPath] + '/' + IIF(t.nodetype = 2,'@','')
+ t.localname AS VARCHAR(1000))
+ N'['
+ CAST(ROW_NUMBER() OVER(PARTITION BY t.localname ORDER BY (SELECT 1)) AS NVARCHAR)
+ N']' AS [XPath]
FROM rs AS t
INNER JOIN cte AS a ON t.ParentId = a.id
)
SELECT ID,ParentID,[Path],REPLACE([XPath],'[1]/#text[1]','') AS XPath,[text] AS [Value]
FROM cte
WHERE [text] IS NOT NULL
AND CAST([text] AS VARCHAR(30)) = '12345'
ORDER BY [Path];
EXEC sp_xml_removedocument @DocHandle;
输出
+----+----------+---------------------+--------------------------------------------------------------+-------+
| ID | ParentID | Path | XPath | Value |
+----+----------+---------------------+--------------------------------------------------------------+-------+
| 35 | 11 | 0,11,35 | /Parent[1]/TestKey1 | 12345 |
| 43 | 25 | 0,12,13,20,23,25,43 | /Parent[1]/Answers[1]/AnswersList[1]/Entry[2]/value[1]/@Text | 12345 |
| 31 | 6 | 0,2,3,6,31 | /Parent[1]/DataExtensions[1]/DataItem[1]/value | 12345 |
| 44 | 26 | 0,26,44 | /Parent[1]/TestKey2 | 12345 |
| 46 | 28 | 0,28,46 | /Parent[1]/TestKey4 | 12345 |
+----+----------+---------------------+--------------------------------------------------------------+-------+
,
.. JfF ..
declare @x xml = N'<Parent>........';
select t.col.value('.','nvarchar(max)') as thepath
from
(values(@x.query('
let $theval := "12345"
for $e in (//*[text()=$theval],//@*[.=$theval])
return
<p>
{
for $i in ($e/../../../../..,$e/../../../..,$e/../../..,$e/../..,$e/..,$e)[..] (: max depth=6 :)
let $k := if ($i/@key) then concat("[@key=(""",$i/@key,""")]") else ""
return text{concat("/",local-name($i),$k)}
}
{if ($e instance of element()) then "/text()" else ""}
</p>
'))) as v(x)
cross apply v.x.nodes('/p') as t(col);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。