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



我正在开发一个在新模式和旧模式之间映射数据的系统。在某些情况下,我希望通过基于属性值定位元素节点并在文本节点上执行插入或更新来更新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|text)?'"

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

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]"似乎是多余的。

我可能在语法或概念上犯了一个简单的错误,但到目前为止我还无法对其进行排序。如果有任何帮助,我将不胜感激。

看看这个:

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;

最新更新