如何将XML文本节点添加到由属性值查询的XML片段

时间:2016-04-05 14:39:25

标签: sql-server xml sql-server-2012

我正在研究一种在新架构和旧架构之间映射数据的系统。在某些情况下,我想通过基于属性值定位元素节点并在文本节点上执行插入或更新来更新xml字段。我已经研究了如何处理更新案例,但是我遇到了插入问题,即文本节点不存在的情况:

以下结果为预期结果:

DECLARE @sample xml;
SET @sample = '<CustomFields>
                <CustomField1 MapsTo="LegacyField1"></CustomField1>
                <CustomField2 MapsTo="LegacyField2"></CustomField2>
                <CustomField3 MapsTo="LegacyField3"></CustomField3>
            </CustomFields>'

SET @sample.modify('insert text{"new field value"} into (/CustomFields/CustomField2)[1]')

结果:

<CustomFields>
  <CustomField1 MapsTo="LegacyField1" />
  <CustomField2 MapsTo="LegacyField2">new field value</CustomField2>
  <CustomField3 MapsTo="LegacyField3" />
</CustomFields>

但是,当我使用MapsTo属性值查询目标节点时,我得到错误或结果不好:

SET @sample.modify('insert text{"new field value"} into (/CustomFields/child::node()[@MapsTo="LegacyField2"])[1]')

导致以下错误:“XQuery [modify()]:'insert into'的目标必须是元素/文档节点,找到'(element(*,xdt:untyped)| comment | processing-instruction |文字)?'“

如果我在一个单独的操作中抓取目标节点,那么:

DECLARE @node XML = @sample.query('/CustomFields/child::node()[@MapsTo="LegacyField2"][1]')

我得到了预期的节点:

<CustomField2 MapsTo="LegacyField2" />

但是,如果我然后运行修改:插入如下:

SET @node.modify('insert text{"new field value"} into (self::node())[1]')

我得到以下意外结果:

<CustomField2 MapsTo="LegacyField2" />new field value

我正在寻找的是:

<CustomField2 MapsTo="LegacyField2">new field value</CustomField2>

BTW:最后两个操作的索引元素“[1]”似乎是多余的。

我可能会犯一个语法或概念的简单错误,但到目前为止我还没能对它进行排序。非常感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

检查出来:

DECLARE @sample xml;
SET @sample = '<CustomFields>
                <CustomField1 MapsTo="LegacyField1"></CustomField1>
                <CustomField2 MapsTo="LegacyField2"></CustomField2>
                <CustomField3 MapsTo="LegacyField3"></CustomField3>
            </CustomFields>';

--directly into Element named CustomField2
SET @sample.modify('insert text{"new field value"} into (/CustomFields/CustomField2)[1]');

--per named "MapsTo" into LegacyField1
SET @sample.modify('insert text{"111"} into (/CustomFields/*[@MapsTo="LegacyField1"])[1]');

--per dynamically named "MapsTo" into LegacyField
DECLARE @target VARCHAR(100)='LegacyField3';
SET @sample.modify('insert text{"333"} into (/CustomFields/*[@MapsTo=sql:variable("@target")])[1]');

SELECT @sample;