假设表列中有以下 XML:
假设表列中有以下 XML:
<UserFields>
<UserField>
<Name>UserName</Name>
<Value>test_user</Value>
</UserField>
<UserField>
<Name>Age</Name>
<Value>24</Value>
</UserField>
<UserField>
<Name>Password</Name>
<Value>test1234!</Value>
</UserField>
<UserField>
<Name>AgentPassword</Name>
<Value>1234Test!</Value>
</UserField>
</UserFields>
<ActionAttributes>
<Action>
<Name>LoginPassword</Name>
<Value>Test123!</Value>
</Action>
</ActionAttributes>
我想查询 XML 以查找任何具有 <Name>
包含该单词 text()
的节点 password
,并将节点的文本替换 <Value>
为星号。在示例中,将有三次替换,最终我会得到以下 XML。
<UserFields>
<UserField>
<Name>UserName</Name>
<Value>test_user</Value>
</UserField>
<UserField>
<Name>Age</Name>
<Value>24</Value>
</UserField>
<UserField>
<Name>Password</Name>
<Value>********</Value>
</UserField>
<UserField>
<Name>AgentPassword</Name>
<Value>********</Value>
</UserField>
</UserFields>
<ActionAttributes>
<Action>
<Name>LoginPassword</Name>
<Value>********</Value>
</Action>
</ActionAttributes>
我想出了这个:
SET @MyDoc.modify('
replace value of (//UserField[Name="Password"]/Value/text())[1]
with "********"
');
该代码的问题是:
<Name>
因此它只能找到“密码”而不是其他变体。
如果用英语来说,我会说:
\'对于具有 <Name>
和 <Value>
子节点的任何节点。 如果子节点 <Name>
包含单词“密码”,则 <Value>
用星号替换子节点的文本。\'
XPath 表达式 必须定义单个节点
表达式1
标识要更新其值的节点。它必须仅标识单个节点。也就是说,Expression1 必须是静态单例。如果 XML 是类型化的,则节点的类型必须是简单类型。当选择多个节点时,会引发错误。
使用 SQL 变量可以避免对表达式中的谓词进行硬编码。
DECLARE @Name VARCHAR(50) = 'Password';
DECLARE @NewValue VARCHAR(50) = '********';
SET @MyDoc.modify('
replace value of (//UserField[Name = sql:variable("@Name")]/Value/text())[1]
with sql:variable("@NewValue")
');
迭代可能的值
DECLARE @myDoc XML;
DECLARE @Name VARCHAR(50);
DECLARE @parent VARCHAR(50);
DECLARE @NewValue VARCHAR(50) = '********';
DECLARE @rowid int;
DECLARE @tnames TABLE(
rowid iNT,
names VARCHAR(50),
parent VARCHAR(50)
);
SET @myDoc = '<root>
<UserFields>
<UserField>
<Name>UserName</Name>
<Value>test_user</Value>
</UserField>
<UserField>
<Name>Age</Name>
<Value>24</Value>
</UserField>
<UserField>
<Name>Password</Name>
<Value>test1234!</Value>
</UserField>
<UserField>
<Name>AgentPassword</Name>
<Value>1234Test!</Value>
</UserField>
</UserFields>
<ActionAttributes>
<Action>
<Name>LoginPassword</Name>
<Value>Test123!</Value>
</Action>
</ActionAttributes>
</root>
';
--SELECT @myDoc;
INSERT INTO @tnames (rowid, names, parent)
SELECT ROW_NUMBER() OVER (ORDER BY t.xname) AS ROWID, T.xname.value('(Name/text())[1]', 'varchar(max)') as names, T.xname.value('(local-name(.))[1]', 'varchar(max)') as parent
FROM @myDoc.nodes('//*[Name[contains(., "Password")]]') T(xname);
SELECT * FROM @tnames;
WHILE (SELECT COUNT(1) FROM @tnames) > 0
BEGIN
SELECT @rowid = rowid, @Name = names, @parent= parent FROM @tnames;
SET @MyDoc.modify('
replace value of (//*[local-name() = sql:variable("@parent")][Name = sql:variable("@Name")]/Value/text())[1]
with sql:variable("@NewValue")
');
DELETE FROM @tnames where rowid = @rowid;
--SELECT ROW_NUMBER() OVER (ORDER BY t.xname) AS ROWID, T.xname.value('(Name/text())[1]', 'varchar(max)') as names, T.xname.value('(Value/text())[1]', 'varchar(max)') as value
--FROM @myDoc.nodes('//*[local-name() = sql:variable("@parent")][Name = sql:variable("@Name")]') T(xname);
END