将存在多个位置的一个子节点值替换为in XML

Replacing the one child node value which is exists multiple places with in XML

我需要用值 'EDWIN CHAND'.

替换子节点 的值 'OBLIGEE ATTORNEY' 和 'saravanan'
BEGIN
DECLARE @LS_EXECUTEQUERY_DESC NVARCHAR(4000),
        @LS_NODE_NAME VARCHAR(100)='user_input_attn_obligee_desc',
        @LS_NAME_DESC  VARCHAR(100) = 'EDWIN CHAND',
        @LS_DOCUMENT_XML XML=cast('<root>
<first>                                                                               
   <var name="user_input_attn_obligee_desc">OBLIGEE ATTORNEY</var> 
</first> 
<second>
 <var name="user_input_attn_obligee_desc">saravanan</var> 
</second>   
<user_input_attn_obligor_desc>OBLIGOR ATTORNEY</user_input_attn_obligor_desc>                          
</root>' AS XML);

 SET @LS_EXECUTEQUERY_DESC = 'SET @LS_DOCUMENT_XML.modify(''replace value of (/root//var[contains(@name,"'+(@LS_NODE_NAME)+'")] /text())[1] with "'+CAST(ISNULL(@LS_NAME_DESC,'') AS VARCHAR)+'"'')';  
 EXEC SP_EXECUTESQL @stmt = @LS_EXECUTEQUERY_DESC ,@params = N'@LS_DOCUMENT_XML xml OUTPUT' ,@LS_DOCUMENT_XML = @LS_DOCUMENT_XML OUTPUT;

             SET @LS_EXECUTEQUERY_DESC = CAST (@LS_DOCUMENT_XML AS VARCHAR(MAX)); 
             SELECT @LS_EXECUTEQUERY_DESC;

END;
             

但是上面的查询只替换了第一次出现的而不是所有出现的。即使它没有抛出任何错误。请有人帮我做这件事。提前致谢。

Needed OUTPUT:
            *<root>
            <first>                                                                               
               <var name="user_input_attn_obligee_desc">EDWIN CHAND</var> 
            </first> 
            <second>
             <var name="user_input_attn_obligee_desc">EDWIN CHAND</var> 
            </second>   
            <user_input_attn_obligor_desc>OBLIGOR ATTORNEY</user_input_attn_obligor_desc>                          
            </root>*

当使用 XML modify() 时,replace operation 必须以单个节点为目标:

Expression1

Identifies a node whose value is to be updated. It must identify only a single node. That is, Expression1 must be a static singleton. If the XML is typed, the type of the node must be a simple type.

这意味着要替换两个单独节点的内容,您将需要两个单独的操作。

SQL 服务器还支持两个 XQuery 扩展函数,sql:column() and sql:variable(),允许您从表达式中引用列和变量值。

我们可以利用 sql:variable() 来简化您的代码以避免使用 sp_executesql...

declare @LS_NODE_NAME nvarchar(100) = N'user_input_attn_obligee_desc',
        @LS_NAME_DESC  nvarchar(100) = N'EDWIN CHAND',
        @LS_DOCUMENT_XML xml = N'<root>
  <first>
    <var name="user_input_attn_obligee_desc">OBLIGEE ATTORNEY</var>
  </first>
  <second>
    <var name="user_input_attn_obligee_desc">saravanan</var>
  </second>
  <user_input_attn_obligor_desc>OBLIGOR ATTORNEY</user_input_attn_obligor_desc>
</root>';

set @LS_DOCUMENT_XML.modify(N'
  replace value of (/root/first/var[@name=sql:variable("@LS_NODE_NAME")]/text())[1]
  with sql:variable("@LS_NAME_DESC")
  ');

set @LS_DOCUMENT_XML.modify(N'
  replace value of (/root/second/var[@name=sql:variable("@LS_NODE_NAME")]/text())[1]
  with sql:variable("@LS_NAME_DESC")
  ');

select @LS_DOCUMENT_XML;

这会产生结果:

<root>
    <first>
        <var name="user_input_attn_obligee_desc">EDWIN CHAND</var>
    </first>
    <second>
        <var name="user_input_attn_obligee_desc">EDWIN CHAND</var>
    </second>
    <user_input_attn_obligor_desc>OBLIGOR ATTORNEY</user_input_attn_obligor_desc>
</root>

解决 OP 的后续评论...

XML modify() 中使用的 XPath 查询有许多限制,阻止您使用简单的解决方案,例如交替路径 (/root/(first,second)/var[@name=sql:variable("@LS_NODE_NAME")]/text()[1]) 或用某些东西替换 [1]就像 while 循环中的 [sql:variable("@NodeIndex")]

如果您事先不知道需要匹配多少个节点,或者所有元素的特定 XPath,可以使用 // (descendant-or-self)轴说明符连同 XML exist() method 然后简单地替换 text() 用于尚未匹配的节点,例如以下 SQL...

declare @ModifyCount int = 0;
while (@ModifyCount < 10 and @LS_DOCUMENT_XML.exist('//var[@name=sql:variable("@LS_NODE_NAME")][text()!=sql:variable("@LS_NAME_DESC")]') = 1)
begin
  set @LS_DOCUMENT_XML.modify(N'
    replace value of (//var[@name=sql:variable("@LS_NODE_NAME")][text()!=sql:variable("@LS_NAME_DESC")]/text())[1]
    with sql:variable("@LS_NAME_DESC")
    ');
  set @ModifyCount += 1;
end
select @ModifyCount, @LS_DOCUMENT_XML;

不过,这方面的问题包括:

  1. //var 没有关注任何上升节点层次结构,因此可能并不总是以您期望的路径为目标。
  2. 为了避免无限循环,请不要单独信任 exist() - 始终包含一个保护计数器,例如 @ModifyCount,其递归限制为 10