How to avoid namespace in child nodes using FOR XML PATH?
Asked Answered
H

3

8

I want to create a sitemap xml file (including images) directly from the database without another process (like transformation or another trick).

My query is:

;WITH XMLNAMESPACES(
    DEFAULT 'http://www.sitemaps.org/schemas/sitemap/0.9',
    'http://www.google.com/schemas/sitemap-image/1.1' as  [image] )  
SELECT  
    (SELECT             
        'mysite'    as [loc],
        (select   
            'anotherloc'
            as [image:loc]
        for XML path('image:image'), type
        )
    for xml path('url'), type
)
for xml path('urlset'), type

Returns:

<urlset xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <loc>mysite</loc>
    <image:image xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <image:loc>anotherloc</image:loc>
    </image:image>
  </url>
</urlset>

But I need this output, without repeated namespace declaration:

<urlset xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>mysite</loc>
    <image:image>
      <image:loc>anotherloc</image:loc>
    </image:image>
  </url>
</urlset>
Headpin answered 10/10, 2012 at 15:56 Comment(2)
Related on DBAKenelm
Possible duplicate of How do I remove redundant namespace in nested query when using FOR XML PATHPetrel
B
4

I'm sure you realise that the additional otiose namespace declarations don't change the meaning of the XML document, so if the result is going to be consumed by an XML-conformant tool, they shouldn't matter. Nevertheless I know there are some tools out there which don't do XML Namespaces correctly, and in a large XML instance superfluous repeated namespace declarations can bloat the size of the result significantly, which may cause its own problems.

In general there is no getting around the fact that each SELECT...FOR XML statement within the scope of a WITH XMLNAMESPACES prefix will generate namespace declarations on the outermost XML element(s) in its result set, in all XML-supporting versions of SQL Server up to SQL Server 2012.

In your specific example, you can get fairly close to the desired XML by separating the SELECTs rather than nesting them, and using the ROOT syntax for the enveloping root element, thus:

DECLARE @inner XML;
WITH XMLNAMESPACES('http://www.google.com/schemas/sitemap-image/1.1' as  [image])   
SELECT @inner =
(   
    SELECT    
        'anotherloc' AS [image:loc] 
    FOR XML PATH('image:image'), TYPE 
)

;WITH XMLNAMESPACES( 
    DEFAULT 'http://www.sitemaps.org/schemas/sitemap/0.9'
)   
SELECT              
        'mysite'    AS [loc], 
        @inner
FOR XML PATH('url'), ROOT('urlset'), TYPE 

The result being:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>mysite</loc>
    <image:image xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns="">
      <image:loc>anotherloc</image:loc>
    </image:image>
  </url>
</urlset>

But this approach doesn't provide a completely general solution to the problem.

Belleslettres answered 11/10, 2012 at 8:53 Comment(0)
N
1

You can use UDF. Example:

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')

Result:

<Parent xmlns="http://www...com/content">
  <Child xmlns="">
    <ChildElement>1</ChildElement>
  </Child>
</Parent>
<Parent xmlns="http://www...com/content">
  <Child xmlns="">
    <ChildElement>1</ChildElement>
  </Child>
</Parent>
Narbonne answered 12/8, 2014 at 15:54 Comment(0)
T
0

Maybe too late for answer, but this is a quick solution.

`DECLARE @PageNumber Int = 1;
DECLARE @siteMapXml XML ;
;WITH XMLNAMESPACES (
    'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd' as "schemaLocation", 
    'http://www.w3.org/2001/XMLSchema-instance' as xsi,
    'http://www.google.com/schemas/sitemap-image/1.1' as [image],
    DEFAULT 'http://www.sitemaps.org/schemas/sitemap/0.9'
    )
        SELECT @siteMapXml =      (

                                    SELECT   
                                       Slug loc,
                                       convert(varchar(300),[Image])  as [image:image/image:loc] 
                                       ,
                                       Convert(char(10), UpdatedOnUtc, 126) as lastmod,
                                       'hourly' as changefreq,
                                       '0.5' as priority
                                    FROM Products(NOLOCK) 
                                    WHERE Pagenumber = @PageNumber

FOR XML PATH ('url'), ROOT ('urlset'))
SELECT @siteMapXml = REPLACE(CAST(@siteMapXml AS NVARCHAR(MAX)), ' xmlns:schemaLocation=', ' xsi:schemaLocation=')
SELECT @siteMapXml`
Trochilus answered 27/3, 2019 at 19:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.