如何在不插入空命名空间的情况下在Sql Server中插入xml节点?

时间:2014-04-28 20:23:03

标签: sql sql-server xml xpath xml-dml

这是我的源xml看起来如何

的示例
<Catalog xmlns="http://schemas.example.com/stuff/stuff">
  <String Key="Name" Tag="22a41320-bb66-41a9-8806-760d13679c6c">Document Title 1</String>
  <String Key="Name" Tag="023463cf-9237-45b6-ac3f-621b9b09f609">Title for document 2</String>
</Catalog>

我打算循环遍历String节点并将它们转换为Document节点(这只显示循环的第一次迭代)。但是,当我插入新节点时,它会插入一个空名称空间。这是我得到的结果:

<Catalog xmlns="http://schemas.example.com/stuff/stuff">
  <String Key="Name" Tag="023463cf-9237-45b6-ac3f-621b9b09f609">Title for document 2</String>
  <Document xmlns="" Key="Document Title 1" Handle="22a41320-bb66-41a9-8806-760d13679c6c" />
</Catalog>

注意空命名空间。我想完全省略Document节点上的命名空间。

这是我想要的结果

<Catalog xmlns="http://schemas.example.com/stuff/stuff">
  <String Key="Name" Tag="023463cf-9237-45b6-ac3f-621b9b09f609">Title for document 2</String>
  <Document Key="Document Title 1" Handle="22a41320-bb66-41a9-8806-760d13679c6c" />
</Catalog>

以下是您可以使用的完整查询:

declare @temp xml, @newNode xml;

set @temp = cast(
'<Catalog xmlns="http://schemas.example.com/stuff/stuff">
  <String Key="Name" Tag="22a41320-bb66-41a9-8806-760d13679c6c">Document Title 1</String>
  <String Key="Name" Tag="023463cf-9237-45b6-ac3f-621b9b09f609">Title for document 2</String>
</Catalog>' as xml)

select 'before', @temp

set @newNode = CAST(
  '<Document Key="' + @temp.value('declare default element namespace "http://schemas.example.com/stuff/stuff"; (/Catalog/String/text())[1]', 'varchar(max)') + 
  '" Handle="' + @temp.value('declare default element namespace "http://schemas.example.com/stuff/stuff"; (/Catalog/String/@Tag)[1]', 'varchar(50)') + '"  />' 
as xml)

set @temp.modify('declare default element namespace "http://schemas.example.com/stuff/stuff"; insert sql:variable("@newNode") into (/Catalog)[1] ')
set @temp.modify('declare default element namespace "http://schemas.example.com/stuff/stuff"; delete (/Catalog/String)[1]')

select 'after', @temp

3 个答案:

答案 0 :(得分:1)

我尝试了各种方法来解决这个问题

  • 与xmlnamespaces一起使用:无变化
  • 使用明确定义的名称空间:无变化
  • 使用与父命令相同的命名空间:导致将默认命名空间插入“文档”节点
  • 使用modify / delete删除空命名空间:不会删除xmlns属性
  • 在modify / insert中动态插入值:“XML数据类型方法的参数1”modify“必须是字符串文字。”

<强>解决方案

所以最后一个错误让我思考,它会插入我想要的节点,没有命名空间,只要它是一个字符串文字。所以我做到了。

  1. 插入空属性
  2. 的空节点
  3. 使用modify / replace在插入后填写属性值
  4. 以下是它的样子

    declare @temp xml
    
    set @temp = cast(
    '<Catalog xmlns="http://schemas.example.com/stuff/stuff">
      <String Key="Name" Tag="22a41320-bb66-41a9-8806-760d13679c6c">Document Title 1</String>
      <String Key="Name" Tag="023463cf-9237-45b6-ac3f-621b9b09f609">Title for document 2</String>
    </Catalog>' as xml)
    
    select 'before', @temp
    
    while (@temp.value('declare default element namespace "http://schemas.example.com/stuff/stuff"; count(/Catalog/String)', 'int') > 0)
    begin
    SET @temp.modify('declare default element namespace "http://schemas.example.com/stuff/stuff"; insert <Document Key="" Handle="" /> into (/Catalog)[1] ')
    SET @temp.modify('declare default element namespace "http://schemas.example.com/stuff/stuff"; replace value of (/Catalog/Document[@Handle=""]/@Handle)[1] with (/Catalog/String/@Tag)[1]')
    SET @temp.modify('declare default element namespace "http://schemas.example.com/stuff/stuff"; replace value of (/Catalog/Document[@Key=""]/@Key)[1] with (/Catalog/String/text())[1]')
    SET @temp.modify('declare default element namespace "http://schemas.example.com/stuff/stuff"; delete (/Catalog/String)[1]')
    end
    
    select 'after', @temp
    

答案 1 :(得分:0)

为什么不替换所需的节点,而不是使用modifyINSERT进行循环和使用DELETE,而不是替换所需的节点:

declare @temp xml, @newNode xml;

set @temp = cast(
'<Catalog xmlns="http://schemas.example.com/stuff/stuff">
  <String Key="Name" Tag="22a41320-bb66-41a9-8806-760d13679c6c">Document Title 1</String>
  <String Key="Name" Tag="023463cf-9237-45b6-ac3f-621b9b09f609">Title for document 2</String>
</Catalog>' as xml)

SELECT CAST(REPLACE(CAST(@temp AS NVARCHAR(MAX)), 'String', 'Catalog') AS XML)

答案 2 :(得分:0)

此替换用于在执行modify()插入

后删除空名称空间属性xmlns=""
UPDATE dbo.TableName
SET TableXmlColumn = CONVERT(XML, REPLACE(CONVERT(NVARCHAR(MAX), TableXmlColumn), N'xmlns=""',''))