I have the following SQL query:
DECLARE @XMLDOC XML
SET @XMLDOC = '<Feed><Product><Name>Foo</Name></Product></Feed>'
SELECT x.u.value('Name[1]', 'varchar(100)') as Name
from @XMLDOC.nodes('/Feed/Product') x(u)
This returns:
Name
----
Foo
However, if my <Feed>
node has an xmlns
attribute, then this doesn't return any results:
DECLARE @XMLDOC XML
SET @XMLDOC = '<Feed xmlns="bar"><Product><Name>Foo</Name></Product></Feed>'
SELECT x.u.value('Name[1]', 'varchar(100)') as Name
from @XMLDOC.nodes('/Feed/Product') x(u)
Returns:
Name
----
This only happens if I have an xmlns
attribute, anything else works fine.
Why is this, and how can I modify my SQL query to return results regardless of the attributes?
You can retrieve multiple values from the rowset. For example, you can apply the value() method to the rowset returned by nodes() and retrieve multiple values from the original XML instance. The value() method, when applied to the XML instance, returns only one value.
XML data can be queried using an SQL fullselect or with the SQL/XML query functions of XMLQUERY and XMLTABLE. The XMLEXISTS predicate can also be used in SQL queries on XML data.
You should use the query() Method if you want to get a part of your XML. If you want the value from a specific node you should use value() Method. Update: If you want to shred your XML to multiple rows you use nodes() Method.
SQL Server provides the XQuery feature to querying XML data type or querying with the XML column with the XPATH. Using XQuery, users can Insert, Update and Delete with the XML nodes and node values in an XML column.
If your XML document has XML namespaces, then you need to consider those in your queries!
So if your XML looks like your sample, then you need:
-- define the default XML namespace to use
;WITH XMLNAMESPACES(DEFAULT 'bar')
SELECT
x.u.value('Name[1]', 'varchar(100)') as Name
from
@XMLDOC.nodes('/Feed/Product') x(u)
Or if you prefer to have explicit control over which XML namespace to use (e.g. if you have multiple), use XML namespace prefixes:
-- define the XML namespace
;WITH XMLNAMESPACES('bar' as b)
SELECT
x.u.value('b:Name[1]', 'varchar(100)') as Name
from
@XMLDOC.nodes('/b:Feed/b:Product') x(u)
As well as the XMLNAMESPACES
solution, you can also use the hideously bulky local-name
syntax...
DECLARE @XMLDOC XML
SET @XMLDOC = '<Feed xmlns="bar"><Product><Name>Foo</Name></Product></Feed>'
SELECT x.u.value('*[local-name() = "Name"][1]', 'varchar(100)') as Name
from @XMLDOC.nodes('/*[local-name() = "Feed"]/*[local-name() = "Product"]') x(u)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With