将存在多个位置的一个子节点值替换为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;
不过,这方面的问题包括:
//var
没有关注任何上升节点层次结构,因此可能并不总是以您期望的路径为目标。
- 为了避免无限循环,请不要单独信任
exist()
- 始终包含一个保护计数器,例如 @ModifyCount
,其递归限制为 10
。
我需要用值 'EDWIN CHAND'.
替换子节点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;
不过,这方面的问题包括:
//var
没有关注任何上升节点层次结构,因此可能并不总是以您期望的路径为目标。- 为了避免无限循环,请不要单独信任
exist()
- 始终包含一个保护计数器,例如@ModifyCount
,其递归限制为10
。