【问题标题】:How to insert xml node in Sql Server without inserting empty namespace?如何在 Sql Server 中插入 xml 节点而不插入空命名空间?
【发布时间】:2014-04-28 20:23:02
【问题描述】:

这是我的源 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

【问题讨论】:

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


    【解决方案1】:

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

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

    解决方案

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

    1. 插入具有空属性的空节点
    2. 插入后使用 modify/replace 填写属性值

    这是它的外观示例

    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
    

    【讨论】:

      【解决方案2】:

      与其循环使用modifyINSERTDELETE,不如直接替换期望节点:

      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)
      

      【讨论】:

      • 除了更改节点的名称之外,我还更改了属性的名称并根据字符串节点的文本内容创建了一个新属性。另外,在 xml 上进行文本替换有点糟糕。在我的示例中,如果“字符串”这个词是标题的一部分,那么它也会修改我们不想要的标题。
      【解决方案3】:

      此替换可在您执行 modify() 插入后删除空的命名空间属性 xmlns=""

      UPDATE dbo.TableName
      SET TableXmlColumn = CONVERT(XML, REPLACE(CONVERT(NVARCHAR(MAX), TableXmlColumn), N'xmlns=""',''))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-09
        • 2019-09-13
        • 1970-01-01
        • 1970-01-01
        • 2015-09-10
        相关资源
        最近更新 更多