T-SQL 替换 XML 节点

use*_*794 5 xml t-sql sql-server

我想用新节点替换 XML 节点。我正在尝试使其动态化,因此替换节点名称是一个变量

DECLARE @xmlSource AS XML = '<Root><Transactions><ReplaceMe>This information should be gone</ReplaceMe></Transactions></Root>'
DECLARE @xmlInsert AS XML = '<NewNode>New Information</NewNode>'
DECLARE @NodeName NVARCHAR(500) = 'ReplaceMe'
Run Code Online (Sandbox Code Playgroud)

生成的 XML 应如下所示:

<Root><Transactions><NewNode>New Information</NewNode></Transactions></Root>
Run Code Online (Sandbox Code Playgroud)

Shn*_*ugo 3

没有直接的方法可以将一个完整的节点替换为另一个节点。

但您可以删除它并插入新的:

DECLARE @xmlSource AS XML = '<Root><Transactions><ReplaceMe>This information should be gone</ReplaceMe></Transactions></Root>'
DECLARE @xmlInsert AS XML = '<NewNode>New Information</NewNode>'
DECLARE @NodeName NVARCHAR(500) = 'ReplaceMe'

SET @xmlSource.modify('delete /Root/Transactions/*[local-name(.) eq sql:variable("@NodeName")]');

SELECT @xmlSource; --ReplaceMe is gone...

SET @xmlSource.modify('insert sql:variable("@xmlInsert") into (/Root/Transactions)[1]');

SELECT @xmlSource; 
Run Code Online (Sandbox Code Playgroud)

结果

<Root>
  <Transactions>
    <NewNode>New Information</NewNode>
  </Transactions>
</Root>
Run Code Online (Sandbox Code Playgroud)

更新通用解决方案

从您的评论中我了解到,您对 XML 一无所知,只需要将您知道名称的一个节点替换为另一个节点...

这个解决方案是基于字符串的(无论如何都是超级丑陋的)并且有一些缺陷:

  • 如果有多个节点同名,则只取第一个
  • 如果该节点多次存在且内容相同,则两处都会被替换
  • 如果您的 xml 包含CDATA-sections,它们将被隐式转换为正确转义的普通 XML。没有语义损失,但这可能会破坏结构验证......

即使对于特殊字符,这也应该有效,因为所有转换都是在 XML 之间NVARCHAR进行的。转义字符两侧应保持相同。

否则,必须使用递归方法来获取节点的完整路径并动态构建我的第一个语句。这个更干净,但更重......

DECLARE @xmlSource AS XML = '<Root><Transactions><ReplaceMe>This information should be gone</ReplaceMe></Transactions></Root>'
DECLARE @xmlInsert AS XML = '<NewNode>New Information</NewNode>'
DECLARE @NodeName NVARCHAR(500) = 'ReplaceMe'

SELECT 
CAST( 
REPLACE(CAST(@xmlSource AS NVARCHAR(MAX))
       ,CAST(@xmlSource.query('//*[local-name(.) eq sql:variable("@NodeName")][1]') AS NVARCHAR(MAX))
       ,CAST(@xmlInsert AS NVARCHAR(MAX))
        )
AS XML) 
Run Code Online (Sandbox Code Playgroud)