Parsing XQuery with an Xml Loose @Variable
Assuming an Xml document similar to this (viz with all the attributes on one element):
DECLARE @xmlData XML =
N'<Reports xmlns:x="http://foo">
<x:InquiryResponse>
<x:ReportData>
<x:AccountDetails>
<x:Account x:primarykey="pk" x:seq="sq" x:id="id"
x:ReportedDate="2014-01-01T00:00:00" />
</x:AccountDetails>
</x:ReportData>
</x:InquiryResponse>
</Reports>';
You can scrape the attributes out as follows:
WITH XMLNAMESPACES('http://foo' AS x)
select
Nodes.node.value('(@x:primarykey)[1]', 'varchar(50)') AS c_val,
Nodes.node.value('(@x:seq)[1]', 'varchar(50)') AS c_val2,
Nodes.node.value('(@x:id)[1]', 'varchar(50)') AS c_val3,
Nodes.node.value('(@x:ReportedDate)[1]', 'DATETIME') as someDateTime
FROM
@xmlData.nodes('/Reports/x:InquiryResponse/x:ReportData/x:AccountDetails/x:Account')
AS Nodes(node);
- Attributes don't need
text()
as they are automatically strings
- It is fairly unusual to have attributes in a namespace - drop the xmlns alias prefix if they aren't.
SqlFiddle here
Edit - Parsing Xml Column
- Namespace dropped from the attributes
-Assumed that you have the data in a table, not a variable, hence the
APPLY
requirement. Note that OUTER APPLY
will return nulls, e.g. useful only if you have rows with
empty Xml or missing Xml Elements. CROSS APPLY
is the norm (viz
applying the xpath to each row selected on the LHS table)
- Elements are accessed similar to attributes, just without
@
WITH XMLNAMESPACES('http://foo' AS x)
select
Nodes.node.value('(@seq)[1]', 'varchar(50)') AS c_val2,
Nodes.node.value('(@id)[1]', 'varchar(50)') AS c_val3,
Nodes.node.value('(@ReportedDate)[1]', 'DATETIME') as someDateTime,
Nodes.node.value('(x:AccountNumber)[1]', 'VARCHAR(50)') as accountNumber
FROM
MyXmlData z
CROSS APPLY
z.XmlColumn.nodes('/Reports/x:InquiryResponse/x:ReportData/x:AccountDetails/x:Account')
AS Nodes(node);
Updated Fiddle
Edit Xml File off Disk
Here's the same thing for an xml file read from disk. Note that once you have the data in an XML
variable (@MyXmlData
) that you don't need to CROSS APPLY
to anything - just supply xpath to select the appropriate node, and then scrape out the elements and attributes.
DECLARE @MyXmlData XML;
SET @MyXmlData =
( SELECT * FROM OPENROWSET ( BULK N'c: empfile3098.xml', SINGLE_CLOB ) AS MyXmlData );
-- Assuming all on the one element, no need for all the applies
-- attributes don't have a text axis (they are automatically strings
WITH XMLNAMESPACES('http://foo' AS x)
select
Nodes.node.value('(@seq)[1]', 'varchar(50)') AS c_val2,
Nodes.node.value('(@id)[1]', 'varchar(50)') AS c_val3,
Nodes.node.value('(@ReportedDate)[1]', 'DATETIME') as someDateTime,
Nodes.node.value('(x:AccountNumber)[1]', 'VARCHAR(50)') as accountNumber
FROM
@MyXmlData.nodes('/Reports/x:InquiryResponse/x:ReportData/x:AccountDetails/x:Account')
AS Nodes(node);
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…