I have a question about using SQL Server FOR XML to create XML documents with namespaces. I need to create a document like below where there is a namespace definition in the root element (xmlns:ijk="h:/i.j.k"
), and a namespace reference in a child element attribute (ijk:LMNO="3333"
).
I am generating the XML to POST to a Web service:
<ROOT xmlns:ijk="h:/i.j.k" RSTU="1111">
<CHILD CDEF="2222" ijk:LMNO="3333" />
</ROOT>
I wrote this first sample query to get the structure correct before I started fighting with namespaces, and the result is what is expected.
SELECT
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
Result
<ROOT RSTU="1111">
<CHILD CDEF="2222" LMNO="3333" />
</ROOT>
Then I tried using WITH NAMESPACES
to add the namespaces, but SQL Server gets carried away and adds all namespaces to all elements. The target Web service does not accept the XML with the namespace overload (in my real case, there are four levels of elements and three namespaces, and it makes a real mess).
WITH XMLNAMESPACES ('h:/i.j.k' as ijk, 'h:/x.y.z' as xyz)
SELECT
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [ijk:LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
Result:
<ROOT xmlns:xyz="h:/x.y.z" xmlns:ijk="h:/i.j.k" RSTU="1111">
<CHILD xmlns:xyz="h:/x.y.z" xmlns:ijk="h:/i.j.k" CDEF="2222" ijk:LMNO="3333" />
</ROOT>
I read in Books Online that, while not recommended, namespaces can be added like a regular attribute. I tried this, and it generated the proper namespace definitions:
SELECT
[xmlns:ijk] = 'h:/i.j.k',
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
Result:
<ROOT xmlns:ijk="h:/i.j.k" RSTU="1111">
<CHILD CDEF="2222" LMNO="3333" />
</ROOT>
The output above has a good looking namespace definition, but the LMNO attribute does not have its required ijk: namespace reference prefix. I tried adding the namespace reference, but I got an error:
SELECT
[xmlns:ijk] = 'h:/i.j.k',
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [ijk:LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
Result:
Msg 6846, Level 16, State 2, Line 34
XML name space prefix 'ijk' declaration is missing for FOR XML column name 'ijk:LMNO'.
Is it possible to write a T-SQL FOR XML query that generates XML where:
a namespace is defined only in the root element, and
the root element has data attributes other than namespace definitions, and
references to the namespace are used in attribute names in child elements?
I reviewed How do I remove redundant namespace in nested query when using FOR XML PATH. In this topic the root element has only namespace definitions and no data attributes.