I need to replace the values 'OBLIGEE ATTORNEY' and 'saravanan' of child node <var..> by the value '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;
But the above query replace the first occurrence alone not all occurrences. Even it didn't throw any error. Could please some one help me to do this. Thanks in advance.
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>*
When using XML
modify()
thereplace
operation must target a single node:This means that to replace the contents of two separate nodes you will need two separate operations.
SQL Server also supports two XQuery Extension Functions,
sql:column()
andsql:variable()
, which allow you to reference column and variable values from within expressions.We can utilize
sql:variable()
to simplify your code to avoid the use ofsp_executesql
...This yields the result:
To address subsequent comments from the OP...
The XPath query used in XML modify() has a number of limitations that prevent you from using simple solutions such as alternating paths (
/root/(first,second)/var[@name=sql:variable("@LS_NODE_NAME")]/text()[1]
) or replacing[1]
with something like[sql:variable("@NodeIndex")]
in a while loop.If you don't know ahead of time how many nodes need to be matched, or the specific XPath for all of the elements, it is possible to use the
//
(descendant-or-self) axis specifier along with the XMLexist()
method and then simply replace thetext()
for nodes that don't already match, such as with the following SQL...The problems with this, though, include:
//var
isn't paying attention to any ascendant node hierarchy, so may not always target the path(s) you expect.exist()
by itself - always include a Guard Counter such as the@ModifyCount
with its limit of10
recursions.