How do I remove redundant namespace in nested query when using FOR XML PATH

前端 未结 6 1941
长情又很酷
长情又很酷 2020-11-28 12:54

UPDATE: I\'ve discovered there is a Microsoft Connect item raised for this issue here

When using FOR XML PATH

6条回答
  •  刺人心
    刺人心 (楼主)
    2020-11-28 13:32

    It would be really nice if FOR XML PATH actually worked more cleanly. Reworking your original example with @table variables:

    declare @t1 table (c1 int, c2 varchar(50));
    declare @t2 table (c1 int, c2 int, c3 varchar(50));
    insert @t1 values 
        (1, 'Mouse'),
        (2, 'Chicken'),
        (3, 'Snake');
    insert @t2 values
        (1, 1, 'Front Right'),
        (2, 1, 'Front Left'),
        (3, 1, 'Back Right'),
        (4, 1, 'Back Left'),
        (5, 2, 'Right'),
        (6, 2, 'Left');
    
    ;with xmlnamespaces( default 'uri:animal')
    select  a.c2 as "@species",
        (
            select  l.c3 as "text()"
            from    @t2 l
            where   l.c2 = a.c1
            for xml path('leg'), type
        ) as "legs"
    from @t1 a
    for xml path('animal'), root('zoo');
    

    Yields the problem XML with repeated namespace declarations:

    
      
        
          Front Right
          Front Left
          Back Right
          Back Left
        
      
      
        
          Right
          Left
        
      
      
    
    

    You can migrate elements between namespaces using XQuery with wildcard namespace matching (that is, *:elementName), as below, but it can be quite cumbersome for complex XML:

    ;with xmlnamespaces( default 'http://tempuri.org/this/namespace/is/meaningless' )
    select (
        select  a.c2 as "@species",
            (
                select  l.c3 as "text()"
                from    @t2 l
                where   l.c2 = a.c1
                for xml path('leg'), type
            ) as "legs"
        from @t1 a
        for xml path('animal'), root('zoo'), type
    ).query('declare default element namespace "uri:animal";
    
    { for $a in *:zoo/*:animal return
        
        {attribute species {$a/@species}}
        { for $l in $a/*:legs return
            
            { for $m in $l/*:leg return
                { $m/text() }
            }
        }
    }');
    

    Which yields your desired result:

    
      
        
          Front Right
          Front Left
          Back Right
          Back Left
        
      
      
        
          Right
          Left
        
      
      
    
    

提交回复
热议问题