I stumbled over some odd behaviour in connection with prefixed attributes. I know - in general - that in most cases prefixed attributes are not used, as they belong to an element which is in a namespace already. But shortly I tried to answer a question and found something I could not understand, even after some research:
DECLARE @xml XML=
N'<test:root xmlns:test="SomeURL">
<test:SomeElement test:SomeAttribute="yeah!" />
</test:root>';
I can wildcard the namespace:
SELECT @xml.value(N'(/*:root/*:SomeElement/@*:SomeAttribute)[1]',N'nvarchar(max)');
I can give an alias to the namespace:
WITH XMLNAMESPACES('SomeURL' AS ns)
SELECT @xml.value(N'(/ns:root/ns:SomeElement/@ns:SomeAttribute)[1]',N'nvarchar(max)');
I thought - as there is only one namespace - I could use it as default:
WITH XMLNAMESPACES(DEFAULT 'SomeURL')
SELECT @xml.value(N'(/root/SomeElement/@SomeAttribute)[1]',N'nvarchar(max)'); --fails!
If I use the same as above but set a wildcard to the attribute it works:
WITH XMLNAMESPACES(DEFAULT 'SomeURL')
SELECT @xml.value(N'(/root/SomeElement/@*:SomeAttribute)[1]',N'nvarchar(max)');
When I use old fashioned FROM OPENXML
I see, that the attribute is a member of test / SomeURL
namespace, just as all elements:
DECLARE @hdoc INT;
EXEC sp_xml_preparedocument @hdoc OUTPUT, @xml;
SELECT * FROM OPENXML (@hdoc, '//*',3);
EXEC sp_xml_removedocument @hdoc;
The result:
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
| id | parentid | nodetype | localname | prefix | namespaceuri | datatype | prev | text |
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
| 0 | NULL | 1 | root | test | SomeURL | NULL | NULL | NULL |
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
| 2 | 0 | 2 | test | xmlns | NULL | NULL | NULL | NULL |
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
| 5 | 2 | 3 | #text | NULL | NULL | NULL | NULL | SomeURL |
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
| 3 | 0 | 1 | SomeElement | test | SomeURL | NULL | NULL | NULL |
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
| 4 | 3 | 2 | SomeAttribute | test | SomeURL | NULL | NULL | NULL |
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
| 6 | 4 | 3 | #text | NULL | NULL | NULL | NULL | yeah! |
+----+----------+----------+---------------+--------+--------------+----------+------+---------+
This is a tiny issue, as it is easy to find a work around, but I'm curious...
Any light on this?
In XPath, as in XML, the default namespace does not apply to attributes. An element name written without a prefix assumes the default namespace, while an attribute name written without a prefix assumes "no namespace".