MSSQL 2012: delete XML attribute by using a variable - sql-server

Good afternoon,
I would like to delete XML attributes by using a TSQL variable. This is a mimimum working example (TSQL-code):
DECLARE #xml XML;
SET #xml = CONVERT(XML, N'
<recipe>
<parameters>
<parameter name="a" desc="A">ValueA</parameter>
<parameter name="b" desc="B">ValueB</parameter>
<parameter name="c" desc="C">ValueC</parameter>
</parameters>
</recipe>
');
SET #xml.[modify]('delete (/recipe/parameters/parameter/#desc)');
SELECT #xml;
This gives the desired output: all attributes "desc" have been removed:
<recipe>
<parameters>
<parameter name="a">ValueA</parameter>
<parameter name="b">ValueB</parameter>
<parameter name="c">ValueC</parameter>
</parameters>
</recipe>
However, I would like to define a TSQL-variable
DECLARE #attr NVARCHAR(MAX) = N'desc';
How can I pass this to the XQuery modify operation? I can use sql:variable("#attr") inside the XML DML, but how can I use it to address an attribute?
Thanks for any help!

You can use a wildcard when specifying the attribute and then check for the name of the attribute in a predicate.
SET #xml.[modify](
'delete(/recipe/parameters/parameter/#*[local-name() = sql:variable("#attr")])');

Related

Getting the desired view/result of XML in SQL Server (Bulk Insert XML into table)

I want to bulk-insert XML data into SQL Server tables.
What have I achieved so far?
I have successfully loaded the XML file into SQL Server and fetched XML data.
What's the problem Now?
The retrieved XML data is not in the desired format. The column names are not in actual column format. Check the below screenshot for an understanding.
XML to SQL server error
XML file:
<?xml version="1.0" encoding="utf-8"?>
<bulkCmConfigDataFile>
<fileHeader/>
<configData>
<class name="BTS5900">
<object technique="SRAN" vendor="Huawei" version="BTS5900 V100R018C10SPC160">
<class name="ALMCURCFG_BTS5900">
<object>
<parameter name="AID" value="29249"/>
<parameter name="ALVL" value="DEFAULT"/>
<parameter name="ASS" value="DEFAULT"/>
<parameter name="SHLDFLG" value="UNSHIELDED"/>
</object>
<object>
<parameter name="AID" value="65033"/>
<parameter name="ALVL" value="MAJOR"/>
<parameter name="ANM" value="Genset Operation"/>
<parameter name="ASS" value="ENV"/>
<parameter name="SHLDFLG" value="DEFAULT"/>
</object>
<object>
<parameter name="AID" value="65034"/>
<parameter name="ALVL" value="MAJOR"/>
<parameter name="ANM" value="High Temperature"/>
<parameter name="ASS" value="ENV"/>
<parameter name="SHLDFLG" value="DEFAULT"/>
</object>
</class>
</object>
</class>
</configData>
</bulkCmConfigDataFile>
Current result:
AID 29249
ALVL DEFAULT
ASS DEFAULT
SHLDFLG UNSHIELDED
AID 65033
ALVL MAJOR
ANM Genset Operation
ASS ENV
SHLDFLG DEFAULT
AID 65034
ALVL MAJOR
ANM High Temperature
ASS ENV
SHLDFLG DEFAULT
I want to get the XML data into this format:
AID, ALVL, ANM, ASS, SHLDFLG
------------------------------------------------------
29249, DEFAULT, NULL DEFAULT, UNSHIELDED
65033, MAJOR, GENERAL OPERATION, ENV, DEFAULT
65034, MAJOR, HIGH TEMPERATURE, ENV, DEFAULT
There is One Condition:
I don't know the names of the columns. My XML is a huge file that's why I can't add all XML content into the question.
This is my code:
DECLARE #xml xml
SELECT #xml = C FROM OPENROWSET (BULK 'E:\Cell_Sense\CM_Input\my_xml.xml', SINGLE_BLOB) AS Cars(C)
DECLARE #hdoc int
EXEC sp_xml_preparedocument #hdoc OUTPUT, #xml
SELECT *
FROM OPENXML (#hdoc, '/bulkCmConfigDataFile/configData/class/object/class/object/parameter') --'/bulkCmConfigDataFile/configData/class[#name="ALMCURCF"]/object/parameter'
WITH(
name VARCHAR(100),
value VARCHAR(100)
)
EXEC sp_xml_removedocument #hdoc
I have successfully loaded the XML file into SQL Server and got all rowset results but the problem is that the fetched data is not in the desired format (I need to format this according to the Destination Table /View so that I can bulk insert it into my table).
Try something like this:
DECLARE #xml xml
SELECT #xml = C FROM OPENROWSET (BULK 'E:\Cell_Sense\CM_Input\my_xml.xml', SINGLE_BLOB) AS Cars(C)
SELECT
AID = xc.value('(parameter[#name="AID"]/#value)[1]', 'varchar(20)'),
ALVL = xc.value('(parameter[#name="ALVL"]/#value)[1]', 'varchar(20)'),
ANM = xc.value('(parameter[#name="ANM"]/#value)[1]', 'varchar(50)'),
ASS = xc.value('(parameter[#name="ASS"]/#value)[1]', 'varchar(50)'),
SHLDFLG = xc.value('(parameter[#name="SHLDFLG"]/#value)[1]', 'varchar(50)')
FROM
#xml.nodes('/bulkCmConfigDataFile/configData/class/object/class/object') AS XT(XC)
You should get a result something like this:
AID
ALVL
ANM
ASS
SHLDFLG
29249
DEFAULT
NULL
DEFAULT
UNSHIELDED
65033
MAJOR
Genset Operation
ENV
DEFAULT
65034
MAJOR
High Temperature
ENV
DEFAULT

SQL Server 2012 create Xml with default values from xsd

I have imported an xsd, containing 258 elements, into my SQL Server 2012 instance. It is mandatory that all 258 elements are present in the final xml. The issue I am having is that 246 of them will contain default values that are identified in the xsd and I do not how to construct my SQL to populate the xml with the default values.
The following is an example I created that illustrates my issue using a much smaller xsd:
DROP XML SCHEMA COLLECTION TestSchema
GO
CREATE XML SCHEMA COLLECTION TestSchema AS
'<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="document">
<complexType>
<sequence>
<element minOccurs="0" name="field1" type="string" default="1" />
<element name="field2" type="int" />
</sequence>
</complexType>
</element>
</schema>'
GO
declare #xml xml(TestSchema) = null
declare #reccount table(recordcount int not null)
insert into #reccount select 32
set #xml =
(
select
recordcount as field2
from
#reccount
for xml
PATH('document')
)
select #xml
The value of #xml is:
<document>
<field2>32</field2>
</document>
Whereas i was expecting
<document>
<field1>1</field1>
<field2>32</field2>
</document>
Any ideas how I can generate the default value of field1?
Thanks in advance.
Lucky for me I came across the answer fooling around with the select statement above. I just needed to add the field 'field1' with a '' for the data.
set #xml =
(
select
'' as field1,
recordcount as field2
from
#reccount
for xml
PATH('document')
)
That did it.

Import 'xml' into Sql Server

I have a file that is structured like so:
<?xml version="1.0" encoding="UTF-8"?>
<EventSchedule>
<Event Uid="2" Type="Main Event">
<IsFixed>True</IsFixed>
<EventKind>MainEvent</EventKind>
<Fields>
<Parameter Name="Type" Value="TV_Show"/>
<Parameter Name="Name" Value="The Muppets"/>
<Parameter Name="Duration" Value="00:30:00"/>
</Fields>
</Event>
<Event>
...and so on
</Event>
</EventSchedule>
I'm not entirely sure if it is valid XML, however I need to import it into SQL Server but everything I try doesn't seem to work.
Please could anyone point me in the right direction either with some example code or a recommendation on which method to use?
I'd ideally like to get the raw data into a flat table, along the lines of:
Name | Type | Duration | EventKind
The Muppets | TV_Show | 00:30:00 | MainEvent
Finally this is coming from fairly large files and I will need to import the regularly.
Thanks, pugu
Try this:
DECLARE #XML XML = '<EventSchedule>
<Event Uid="2" Type="Main Event">
<IsFixed>True</IsFixed>
<EventKind>MainEvent</EventKind>
<Fields>
<Parameter Name="Type" Value="TV_Show"/>
<Parameter Name="Name" Value="The Muppets"/>
<Parameter Name="Duration" Value="00:30:00"/>
</Fields>
</Event>
<Event Uid="3" Type="Secondary Event">
<IsFixed>True</IsFixed>
<EventKind>SecondaryEvent</EventKind>
<Fields>
<Parameter Name="Type" Value="TV_Show"/>
<Parameter Name="Name" Value="The Muppets II"/>
<Parameter Name="Duration" Value="00:30:00"/>
</Fields>
</Event>
</EventSchedule>'
SELECT
EventUID = Events.value('#Uid', 'int'),
EventType = Events.value('#Type', 'varchar(20)'),
EventIsFixed =Events.value('(IsFixed)[1]', 'varchar(20)'),
EventKind =Events.value('(EventKind)[1]', 'varchar(20)')
FROM
#XML.nodes('/EventSchedule/Event') AS XTbl(Events)
Gives me an output of:
And of course, you can easily do an
INSERT INTO dbo.YourTable(EventUID, EventType, EventIsFixed, EventKind)
SELECT
......
to insert that data into a relational table.
Update: assuming you have your XML in files - you can use this code to load the XML file into an XML variable in SQL Server:
DECLARE #XmlFile XML
SELECT #XmlFile = BulkColumn
FROM OPENROWSET(BULK 'path-to-your-XML-file', SINGLE_BLOB) x;
and then use the above code snippet to parse the XML.
Update #2: if you need the parameters, too - use this XQuery statement:
SELECT
EventUID = Events.value('#Uid', 'int'),
EventType = Events.value('#Type', 'varchar(20)'),
EventIsFixed = Events.value('(IsFixed)[1]', 'varchar(20)'),
EventKind = Events.value('(EventKind)[1]', 'varchar(20)'),
ParameterType = Events.value('(Fields/Parameter[#Name="Type"]/#Value)[1]', 'varchar(20)'),
ParameterName = Events.value('(Fields/Parameter[#Name="Name"]/#Value)[1]', 'varchar(20)'),
ParameterDuration = Events.value('(Fields/Parameter[#Name="Duration"]/#Value)[1]', 'varchar(20)')
FROM
#XML.nodes('/EventSchedule/Event') AS XTbl(Events)
Results in:
You do it by creating a destination table, then a schema mapping file that maps the xml elements to table columns.
Yours might look a bit like this:
create table event (
Type nvarchar(50),
Name nvarchar(50),
Duration nvarchar(50))
and this:
<?xml version="1.0" ?>
<Schema xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:xml:datatypes"
xmlns:sql="urn:schemas-microsoft-com:xml-sql" >
<ElementType name="Type" dt:type="string" />
<ElementType name="Name" dt:type="string" />
<ElementType name="Duration" dt:type="string" />
<ElementType name="EventSchedule" sql:is-constant="1">
<element type="Event" />
</ElementType>
<ElementType name="Event" sql:relation="Event">
<element type="Type" sql:field="Type" />
<element type="Name" sql:field="Name" />
<element type="Duration" sql:field="Duration" />
</ElementType>
</Schema>
Then you can load your XML into your table using the XML bulk loader.
http://support.microsoft.com/kb/316005
If you need to do it without XML variable (from string in table-valued function)
SELECT
--myTempTable.XmlCol.value('.', 'varchar(36)') AS val
myTempTable.XmlCol.query('./ID').value('.', 'varchar(36)') AS ID
,myTempTable.XmlCol.query('./Name').value('.', 'nvarchar(MAX)') AS Name
,myTempTable.XmlCol.query('./RFC').value('.', 'nvarchar(MAX)') AS RFC
,myTempTable.XmlCol.query('./Text').value('.', 'nvarchar(MAX)') AS Text
,myTempTable.XmlCol.query('./Desc').value('.', 'nvarchar(MAX)') AS Description
--,myTempTable.XmlCol.value('(Desc)[1]', 'nvarchar(MAX)') AS DescMeth2
FROM
(
SELECT
CAST('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data-set>
<record>
<ID>1</ID>
<Name>A</Name>
<RFC>RFC 1035[1]</RFC>
<Text>Address record</Text>
<Desc>Returns a 32-bit IPv4 address, most commonly used to map hostnames to an IP address of the host, but it is also used for DNSBLs, storing subnet masks in RFC 1101, etc.</Desc>
</record>
<record>
<ID>2</ID>
<Name>NS</Name>
<RFC>RFC 1035[1]</RFC>
<Text>Name server record</Text>
<Desc>Delegates a DNS zone to use the given authoritative name servers</Desc>
</record>
</data-set>
' AS xml) AS RawXml
) AS b
--CROSS APPLY b.RawXml.nodes('//record/ID') myTempTable(XmlCol);
CROSS APPLY b.RawXml.nodes('//record') myTempTable(XmlCol);
Or from file:
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tfu_RPT_SEL_XmlData]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[tfu_RPT_SEL_XmlData]
GO
CREATE FUNCTION [dbo].[tfu_RPT_SEL_XmlData]
(
#in_language varchar(10)
,#in_reportingDate datetime
)
RETURNS TABLE
AS
RETURN
(
SELECT
--myTempTable.XmlCol.value('.', 'varchar(36)') AS val
myTempTable.XmlCol.query('./ID').value('.', 'varchar(36)') AS ID
,myTempTable.XmlCol.query('./Name').value('.', 'nvarchar(MAX)') AS Name
,myTempTable.XmlCol.query('./RFC').value('.', 'nvarchar(MAX)') AS RFC
,myTempTable.XmlCol.query('./Text').value('.', 'nvarchar(MAX)') AS Text
,myTempTable.XmlCol.query('./Desc').value('.', 'nvarchar(MAX)') AS Description
FROM
(
SELECT CONVERT(XML, BulkColumn) AS RawXml
FROM OPENROWSET(BULK 'D:\username\Desktop\MyData.xml', SINGLE_BLOB) AS MandatoryRowSetName
) AS b
CROSS APPLY b.RawXml.nodes('//record') myTempTable(XmlCol)
)
GO
SELECT * FROM tfu_RPT_SEL_XmlData('DE', CURRENT_TIMESTAMP);
e.g.
DECLARE #bla varchar(MAX)
SET #bla = 'BED40DFC-F468-46DD-8017-00EF2FA3E4A4,64B59FC5-3F4D-4B0E-9A48-01F3D4F220B0,A611A108-97CA-42F3-A2E1-057165339719,E72D95EA-578F-45FC-88E5-075F66FD726C'
-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT
x.XmlCol.value('.', 'varchar(36)') AS val
FROM
(
SELECT
CAST('<e>' + REPLACE(#bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b
CROSS APPLY b.RawXml.nodes('e') x(XmlCol);
So you can have a function like
SELECT * FROM MyTable
WHERE UID IN
(
SELECT
x.XmlCol.value('.', 'varchar(36)') AS val
FROM
(
SELECT
CAST('<e>' + REPLACE(#bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b
CROSS APPLY b.RawXml.nodes('e') x(XmlCol)
)
If you're trying to import your XML as a "pure" XML field you should create a table like this (obviously with many other fields as you want):
CREATE TABLE [dbo].[TableXML](
[ID] [int] IDENTITY(1,1) NOT NULL,
[XmlContent] [xml] NOT NULL -- specify [xml] type
)
Then you can easily insert your XML as a string:
INSERT INTO [dbo].[TableXML]
([XmlContent])
VALUES
('<?xml version="1.0" encoding="UTF-8"?>
<EventSchedule>
<Event Uid="2" Type="Main Event">
<IsFixed>True</IsFixed>
<EventKind>MainEvent</EventKind>
<Fields>
<Parameter Name="Type" Value="TV_Show"/>
<Parameter Name="Name" Value="The Muppets"/>
<Parameter Name="Duration" Value="00:30:00"/>
</Fields>
</Event>
</EventSchedule>')
Then to query start from MSDN t-SQL XML
If you prefer store it as string use a varchar(max) in place of [XML] column type and the same insert. But if you like to query easily I suggest [XML] type. With the flat string approach you need a lot of work unless you will implement some application code to parse it and store in a flat table.
A good approach could be an XML storage in a "compress" TABLE and a VIEW for data retrieve with the flat field disposition.
How to load the below XML data into the SQL
<?xml version="1.0" encoding="utf-8"?>
<DataTable xmlns="SmarttraceWS">
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:MainDataTable="ActivityRecords" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="ActivityRecords">
<xs:complexType>
<xs:sequence>
<xs:element name="ReferenceID" type="xs:long" minOccurs="0" />
<xs:element name="IMEI" type="xs:string" minOccurs="0" />
<xs:element name="Asset" type="xs:string" minOccurs="0" />
<xs:element name="Driver" type="xs:string" minOccurs="0" />
<xs:element name="DateTime" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<DocumentElement xmlns="">
<ActivityRecords diffgr:id="ActivityRecords1" msdata:rowOrder="0">
<ReferenceID>2620443016</ReferenceID>
<IMEI>013795001360346</IMEI>
<Asset>L-93745</Asset>
<Driver>N/A</Driver>
<DateTime>2019-10-14 12:00:35</DateTime>
</ActivityRecords>
</DocumentElement>
</diffgr:diffgram>
</DataTable>

SQL - Read an XML node from a table field

I am using SQL Server 2008. I have a field called RequestParameters in one of my SQL table called Requests with XML data. An example would be:
<RequestParameters xmlns="http://schemas.datacontract.org/2004/07/My.Name.Space" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="1">
<Data z:Id="2" i:type="CheckoutRequest">
<UserGuid>7ec38c44-5aa6-49e6-9fc7-25e9028f2148</UserGuid>
<DefaultData i:nil="true" />
</Data>
</RequestParameters>
I ultimately want to retrieve the value of UserGuid. For that, I am doing this:
SELECT RequestParameters.value('(/RequestParameters/Data/UserGuid)[0]', 'uniqueidentifier') as UserGuid
FROM Requests
However, the results I am seeing are all NULL. What am I doing wrong?
You have to specify the default namespace and use [1] instead of [0].
WITH XMLNAMESPACES(default 'http://schemas.datacontract.org/2004/07/My.Name.Space')
SELECT RequestParameters.value('(/RequestParameters/Data/UserGuid)[1]', 'uniqueidentifier') as UserGuid
FROM Requests;
SQL Fiddle
declare #XML xml
set #XML = "<RequestParameters xmlns="http://schemas.datacontract.org/2004/07/My.Name.Space" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="1">
<Data z:Id="2" i:type="CheckoutRequest">
<UserGuid>7ec38c44-5aa6-49e6-9fc7-25e9028f2148</UserGuid>
<DefaultData i:nil="true" />
</Data>
</RequestParameters>"
select #XML.value('(/RequestParameters/Data /UserGuid)[1]', 'varchar')
'

SQLXML - Search and Query node element?

I have an XML like this stored in an XML datatype column (will have multiple such rows in table)-
<Root xmlns="http://tempuri.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Elem1 type="T1">
<Name type="string" display="First name">John</Name>
<TimeZone display="Time zone">
<DisplayName type="string" display="Display name">GMT Standard Time</DisplayName>
</TimeZone>
</Elem1>
</Root>
How can I filter based on a node element say (using SQL SERVER 2008 R2) - get all 'Elem1' nodes or get all 'Name' nodes or get all TimeZone nodes ? Something like using local-name() function ?
EDIT - Part Solution -
I got the solution partly (see John's reply below and then run this) -
SELECT C1.query('fn:local-name(.)') AS Nodes FROM [dbo].[MyXmlTable] AS MyXML CROSS APPLY MyXML.MyXmlCol.nodes('//*') AS T ( C1 )
The query above returns all the node elements across the TABLE. Now, I want to say filter upon specific elements and return the element and its value or its attribute value. How to achieve this (by using WHERE clause or any other filter mechanism)?
I'm not sure what result you are looking for but something like this perhaps.
declare #T table(XMLCol xml)
insert into #T values
('<Root xmlns="http://tempuri.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Elem1 type="T1">
<Name type="string" display="First name">John</Name>
<TimeZone display="Time zone">
<DisplayName type="string" display="Display name">GMT Standard Time</DisplayName>
</TimeZone>
</Elem1>
</Root>')
declare #Node varchar(50)
set #Node = 'Elem1'
select N.query('.') as Value
from #T as T
cross apply T.XMLCol.nodes('//*[local-name()=sql:variable("#Node")]') as X(N)
Result:
<p1:Elem1 xmlns:p1="http://tempuri.org" type="T1">
<p1:Name type="string" display="First name">John</p1:Name>
<p1:TimeZone display="Time zone">
<p1:DisplayName type="string" display="Display name">GMT Standard Time</p1:DisplayName>
</p1:TimeZone>
</p1:Elem1>
Edit
If you want the actual value instead of the entire XML you can do like this instead.
declare #Node varchar(50)
set #Node = 'TimeZone'
select N.value('.', 'varchar(100)') as Value
from #T as T
cross apply T.XMLCol.nodes('//*[local-name()=sql:variable("#Node")]') as X(N)
Result:
Value
------------------
GMT Standard Time
You can transform XML into table like here:
declare #XML xml='<Root xmlns="http://tempuri.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Elem1 type="T1">
<Name type="string" display="First name">John</Name>
<TimeZone display="Time zone">
<DisplayName type="string" display="Display name">GMT Standard Time</DisplayName>
</TimeZone>
</Elem1>
</Root> '
;WITH XMLNAMESPACES(DEFAULT 'http://tempuri.org'),
numbers as(
SELECT ROW_NUMBER() OVER(ORDER BY o1.object_id,o2.object_id) Num
FROM sys.objects o1 CROSS JOIN sys.objects o2),
c as(
SELECT
b.value('local-name(.)','nvarchar(1000)') Node_Name,
b.value('./text()[1]','nvarchar(1000)') Node_Value,
b.value('count(#*)','nvarchar(MAX)') AttributeCount,
Num Attribute_Number
FROM
#xml.nodes('Root//*') a(b)
CROSS APPLY Numbers
WHERE Num<=b.value('count(#*)','nvarchar(MAX)')
)
SELECT c.Node_Name,c.node_Value,Attribute_Number,
#XML.query('for $Attr in //*/.[local-name(.)=sql:column("Node_Name")]/#*[sql:column("Attribute_Number")] return local-name($Attr)').value('.','nvarchar(MAX)') Attribute_Name,
#XML.value('data(//*/.[local-name(.)=sql:column("Node_Name")]/#*[sql:column("Attribute_Number")])[1]','nvarchar(1000)') Attribute_Value
FROM c
Result:
Node_Name node_Value Attribute_Number Attribute_Name Attribute_Value
Elem1 NULL 1 type T1
Name John 1 type string
Name John 2 display First name
TimeZone NULL 1 display Time zone
DisplayName GMT Standard Time 1 type string
DisplayName GMT Standard Time 2 display Display name
Later you can query this result to get node/attribute value which do you need.
But it works only in your example, when you have only one node and all names are unique. In multinode XML you should use hierarchical numbering like '1-1-2' or something like this. It is much more complicated and i do not suggest to going this way.
It's not clear to me exactly what your output should look like. However, this should get you started:
create table MyXmlTable (MyXmlCol xml)
insert into MyXmlTable (MyXmlCol) values
(
'
<Root xmlns="http://tempuri.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Elem1 type="T1">
<Name type="string" display="First name">John</Name>
<TimeZone display="Time zone">
<DisplayName type="string" display="Display name">GMT Standard Time</DisplayName>
</TimeZone>
</Elem1>
<Elem1 type="T2">
<Name type="string" display="First name">Fred</Name>
<TimeZone display="Time zone">
<DisplayName type="string" display="Display name">EST Standard Time</DisplayName>
</TimeZone>
</Elem1>
</Root>
');
;WITH XMLNAMESPACES(DEFAULT 'http://tempuri.org')
select MyXmlCol.query('/Root/Elem1/Name')
from MyXmlTable
This queries the XML for the "Name" elements -- you can modify the query depending on what kind of output you want exactly. It's a bit long, but the MSDN article on SQLXML is pretty informative:
http://msdn.microsoft.com/en-us/library/ms345117(v=sql.90).aspx
Hope this helps!
John
Update: you can add a where clause something like this. I'm still not clear on what you want the output to look like, but this will filter out the "Elem1" values:
SELECT C1.query('fn:local-name(.)') AS Nodes
FROM [dbo].[MyXmlTable] AS MyXML
CROSS APPLY MyXML.MyXmlCol.nodes('//*') AS T ( C1 )
WHERE CAST(C1.query('fn:local-name(.)') AS NVARCHAR(32)) <> 'Elem1'
One more update; hopefully this is the answer you are looking for!
Try using a wildcard in the query. I had to use dynamic SQL because the XML query() function will only take string literals for paths (you can use sql:variable("#filter") for values, but I wasn't able to get that working for a path.)
DECLARE #filter nvarchar(20)
SET #filter = '*/Elem1'
DECLARE #sqlCommand nvarchar(1000)
SET #sqlCommand =
';WITH XMLNAMESPACES(DEFAULT ''http://tempuri.org'')
select MyXmlCol.query(''' + #filter + ''')
from MyXmlTable'
print #sqlCommand
EXECUTE sp_executesql #sqlCommand, N'#filter nvarchar(20)', #filter = #filter
This will return the Elem1 XML (and all sub-nodes):
<p1:Elem1 xmlns:p1="http://tempuri.org" type="T1">
<p1:Name type="string" display="First name">John</p1:Name>
<p1:TimeZone display="Time zone">
<p1:DisplayName type="string" display="Display name">GMT Standard Time</p1:DisplayName>
</p1:TimeZone>
</p1:Elem1>
<p2:Elem1 xmlns:p2="http://tempuri.org" type="T2">
<p2:Name type="string" display="First name">Fred</p2:Name>
<p2:TimeZone display="Time zone">
<p2:DisplayName type="string" display="Display name">EST Standard Time</p2:DisplayName>
</p2:TimeZone>
</p2:Elem1>
And if you want to pick out "TimeZone" you would do this:
SET #filter = '*/*/TimeZone'

Resources