我想知道如何替换存储在SQL Server数据库中的xml中的子节点名称
示例XML
<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
<Test_Node>Yes</Test_Node>
</ProductionServers>
</ProductionServer>
</CompanyStatus>
我如何将其更改为以下内容:
<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
<Live_Node>Yes</Live_Node>
</ProductionServers>
</ProductionServer>
</CompanyStatus>
基本上唯一的变化是<Test_Node>
重命名为<Live_Node>
,但价值相同。
有一种简单的方法吗?
我的数据库中有大约1000条记录
答案 0 :(得分:1)
使用XQuery,例如:
create function SwitchToLiveNode(@doc xml)
returns xml
as
begin
declare @val varchar(200) = @doc.value('(/CompanyStatus/ProductionServers/ProductionServer/Test_Node)[1]', 'varchar(200)')
declare @newNode xml = concat('<Live_Node>',@val,'</Live_Node>')
SET @doc.modify('
insert sql:variable("@newNode")
as last
into (/CompanyStatus/ProductionServers/ProductionServer)[1]
')
set @doc.modify('delete /CompanyStatus/ProductionServers/ProductionServer/Test_Node')
return @doc
end
go
declare @doc xml = '
<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
<Test_Node>Yes</Test_Node>
</ProductionServer>
</ProductionServers>
</CompanyStatus>'
select dbo.SwitchToLiveNode(@doc)
答案 1 :(得分:1)
这是我的建议
检查出来:
DECLARE @xml XML=
N'<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
<Test_Node a="x" b="y" c="z">Yes</Test_Node>
</ProductionServer>
</ProductionServers>
</CompanyStatus>';
- 这将创建<Test_Node>
及其所有属性(如果有的话),其中包含新元素名称<Live_Node>
:
DECLARE @NewNode XML=
(
SELECT @xml.query(N'let $nd:=(//*[local-name()="Test_Node"])[1]
return
<Live_Node> {$nd/@*}
{$nd/text()}
</Live_Node>
')
);
- 这将首先在原始文件后直接插入"@NewNode"
,并删除原始文件:
SET @xml.modify(N'insert sql:variable("@NewNode") after (//*[local-name()="Test_Node"])[1]');
SET @xml.modify(N'delete (//*[local-name()="Test_Node"])[1]');
SELECT @xml;
结果
<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
<Live_Node a="x" b="y" c="z">Yes</Live_Node>
</ProductionServer>
</ProductionServers>
</CompanyStatus>
DECLARE @xmlTable TABLE (YourXml XML);
INSERT INTO @xmlTable VALUES
(--Test_Node has got attributes
N'<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
<Test_Node a="x" b="y" c="z">Yes</Test_Node>
</ProductionServer>
</ProductionServers>
</CompanyStatus>'
)
,( --different position, no attributes
N'<CompanyStatus>
<ProductionServers>
<Test_Node>Yes</Test_Node>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
</ProductionServer>
</ProductionServers>
</CompanyStatus>'
)
,( --No test node at all
N'<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
</ProductionServer>
</ProductionServers>
</CompanyStatus>'
);
- 可更新CTE返回原始节点和新节点。这可以一次更新:
WITH ReadNode AS
(
SELECT t.YourXml.query(N'let $nd:=(//*[local-name()="Test_Node"])[1]
return
<Live_Node> {$nd/@*}
{$nd/text()}
</Live_Node>
') AS NewNode
,t.YourXml AS Original
FROM @xmlTable AS t
)
UPDATE ReadNode SET Original.modify(N'insert sql:column("NewNode") after (//*[local-name()="Test_Node"])[1]');
UPDATE @xmlTable SET YourXml.modify(N'delete (//*[local-name()="Test_Node"])[1]');
SELECT *
FROM @xmlTable
答案 2 :(得分:0)
虽然您的问题要求SQL的解决方案,但我认为最好的解决方案是使用XML库正确解析XML,这在C#中是最简单的。
幸运的是,您可以在SQL Server中将其用作SQL-CLR存储过程:
CREATE PROCEDURE ReplaceTestNode(@xml xml) AS EXTERNAL NAME StoredProcedures.ReplaceTestNode
不幸的是,您无法使用System.Xml
重命名XML元素。而是创建一个新的替换节点,将其插入与原始节点相同的位置,移动内容(和任何属性),然后删除原始节点。
public static class StoredProcedures {
[SqlProcedure]
public static void ReplaceTestNode(SqlXml data, out SqlXml output) {
XmlDocument doc = new XmlDocument();
using( XmlReader rdr = data.CreateReader() ) {
doc.Load( rdr );
}
ReplaceElementName( doc, "Test_Node", "Live_Node" );
using( XmlReader outRdr = new XmlNodeReader( doc ) ) {
output = new SqlXml( outRdr );
}
}
}
private static void ReplaceElementName(XmlDocument doc, String oldName, String newName) {
XmlNodeList testNodes = doc.GetElementsByTagName( oldName );
List<XmlElement> testElements = testNodes
.Where( n => n.NodeType == XmlNodeType.Element )
.Cast<XmlElement>()
.ToList();
foreach( XmlElement element in testElements ) {
// 1: Create replacement element and insert in the same location:
XmlElement replacement = doc.CreateElement( newName );
element.ParentElement.InsertBefore( replacement, element );
// 2: Move child nodes over
foreach(XmlNode child in element.ChildNodes) {
replacement.AppendChild( child );
}
// 3: Move attributes over
foreach(XmlAttribute attrib in element.Attributes) {
replacement.Attributes.Append( attrib );
}
// 4: Remove
element.ParentElement.Remove( element );
}
}
答案 3 :(得分:0)
一个快速选项是通过Replace()
(更正了你的xml)
示例强>
Update YourTable
set XMLCol = replace(cast(XMLCol as nvarchar(max)),'Test_Node>','Live_Node>')
更新的XML
<CompanyStatus>
<ProductionServers>
<ProductionServer>
<Patch>0</Patch>
<Status>Green</Status>
<Live_Node>Yes</Live_Node>
</ProductionServer>
</ProductionServers>
</CompanyStatus>
编辑 - 如果
Test_Node
具有属性(如戴正确指出的那样)
Update YourTable
set XMLCol = replace(replace(cast(XMLCol as varchar(max)),'</Test_Node>','</Live_Node>'),'<Test_Node>','<Live_Node>')
答案 4 :(得分:0)
更新 TABLE_NAME 设置 COLUMN_NAME = cast(REPLACE(cast( COLUMN_NAME 为VARCHAR(max)),'Test_Node','Live_Node' )作为XML)
[注意:使用此脚本放置表名和目标列名]