Reputation: 13
I'm trying to Parse some XML having multiple nesting levels in SQL. The problem I hit into here is how to write my query generic enough for it to Parse the XML below without having to hard-code the node path e:g
EXEC sp_xml_preparedocument @handle OUTPUT, @xml
INSERT #Root(ID)
SELECT *
FROM OPENXML(@handle, '/Root')
WITH (ID VARCHAR(100))
INSERT #ConditionSet(Operator)
SELECT *
FROM OPENXML(@handle, '/Root/ConditionSet')
WITH (Operator VARCHAR(100))
INSERT #ConditionSet(Operator)
SELECT *
FROM OPENXML(@handle, '/Root/ConditionSet/ConditionSet')
WITH (Operator VARCHAR(100))
INSERT #ConditionSet(Operator)
SELECT *
FROM OPENXML(@handle, '/Root/ConditionSet/ConditionSet/ConditionSet')
WITH (Operator VARCHAR(100))
Is there a better way to Parse the following XML in SQL and represent all data in tabular form?
<?xml version="1.0"?>
-<Root ID="414141" Source="AudienceBuilder">
-<ConditionSet Operator="I">
-<Condition Operator="E" ID="74373">
-<Relationship ID="56756">
<Relationship ID="67868"/>
</Relationship>
-<Value>
<![CDATA[ABC]]>
</Value>
</Condition>
-<ConditionSet Operator="O">
-<Condition Operator="E" ID="6566">
-<Relationship ID="7658">
<Relationship ID="6547"/>
</Relationship>
-<Value>
<![CDATA[DEF]]>
</Value>
</Condition>
-<Condition Operator="E" ID="96967">
-<Relationship ID="3884">
<Relationship ID="9954"/>
</Relationship>
-<Value>
<![CDATA[GHI]]>
</Value>
</Condition>
-<ConditionSet Operator="A">
-<Condition Operator="E" ID="31654">
-<Relationship ID="57894">
<Relationship ID="8532"/>
</Relationship>
-<Value>
<![CDATA[JKL]]>
</Value>
</Condition>
-<Condition Operator="E" ID="65636">
-<Relationship ID="843">
<Relationship ID="7473"/>
</Relationship>
-<Value>
<![CDATA[MNO]]>
</Value>
</Condition>
</ConditionSet>
</ConditionSet>
</ConditionSet>
</Root>
Any inputs/recommendations are highly appreciated :)
Thank you
Zeaous
Upvotes: 0
Views: 3151
Reputation: 755361
Assuming you have your XML in a SQL Server variable called @XML
, you can use the native XQuery support in SQL Server 2005 and newer to do this much more elegantly and efficiently:
DECLARE @XML XML = '...(your XML here).....'
SELECT
RootID = @xml.value('(/Root/@ID)[1]', 'int'),
ConditionSetOperator = XC.value('@Operator', 'varchar(50)'),
ConditionID = XC2.value('@ID', 'int'),
ConditionOperator = XC2.value('@Operator', 'varchar(50)')
FROM
@Xml.nodes('//ConditionSet') AS XT(XC)
CROSS APPLY
xc.nodes('Condition') AS XT2(XC2)
This gives me an output of
With XQuery operators like .nodes()
or .value()
, you can easily "shred" an XML document into relational data and store that as needed.
The first call to @xml.nodes('//ConditionSet')
will get a "pseudo" table for each matching node - so each <ConditionSet>
node will be returned in the "pseudo" table XT
as column XC
, and then I can easily grab attributes (or XML elements) from that XML fragment using XQuery methods like .value()
.
Or I can even grab the list of sub-nodes <Condition>
for each of those <ConditionSet>
nodes - using the CROSS APPLY
with a second call to .nodes()
Upvotes: 1