Default namespace with FOR XML PATH

2019-05-25 21:49发布

问题:

Consider the following SQL:

;WITH XMLNAMESPACES(DEFAULT 'http://www.mynamespace.co.uk')
,CTE_DummyData AS (
    select id=1
)
select TOP 1
    [@ID]=1,
    (select top 1 [@ID] = 1 FROM CTE_DummyData FOR XML PATH ('Child'), TYPE)
from CTE_DummyData
FOR XML PATH ('Parent')

Thie returns the xml:

<Parent xmlns="http://www.mynamespace.co.uk" ID="1">
  <Child xmlns="http://www.mynamespace.co.uk" ID="1" />
</Parent>

What I need is to return the xml with the xmlns declaration on only the root element. eg:

<Parent xmlns="http://www.mynamespace.co.uk" ID="1">
  <Child ID="1" />
</Parent>

Is there a way to do this?

Note: The above SQL is an extreme simplification of the actual code, which produces a complex document, so changing from FOR XML PATH isn't really an option without giving me a couple of days of extra work to do. To be clear on the the top level of the entire document is required to have the NS, and all children should be without.

回答1:

You can use the "query from hell"

;with CTE_DummyData AS (
    select id=1
)
select 1 as tag,
       0 as parent,
       'http://www.mynamespace.co.uk' as [Parent!1!xmlns],
       id as [Parent!1!ID],
       null as [Child!2!ID]
from CTE_DummyData       
union all
select top 1
       2,
       1,
       null,
       null,
       id
from CTE_DummyData       
for xml explicit


回答2:

You could use a UDF to generate child nodes. E.g.

ALTER FUNCTION [dbo].[udf_get_child_section] (
    @serviceHeaderId INT
 )
RETURNS XML

BEGIN

    DECLARE @result XML;

    SELECT @result = 
    (
        SELECT 1 AS 'ChildElement'
        FOR XML PATH('Child')
    )

    RETURN @result

END


GO

DECLARE @Ids TABLE
( 
    ID int 
)

INSERT INTO @Ids
SELECT 1 AS ID 
UNION ALL
SELECT 2 AS ID

;WITH XMLNAMESPACES (DEFAULT 'http://www...com/content')
SELECT 
    [dbo].[udf_get_child_section](ID)
FROM 
    @Ids
FOR XML PATH('Parent')