不使用sql:variable将节点插入XML

时间:2018-12-12 18:16:17

标签: xml sql-server-2008-r2 xquery

我已经遍及整个网络(包括SO,但我可能会错过它)寻找一种方法,可以将节点插入到包含在变量中的现有XML中,而无需先在变量中创建XML作为节点的字符串想要插入并使用“ set @ XMLVariable01.modify('insert sql:variable(” @ XMLVariable02“)as ...”。

从下面的示例中,我想得到最终结果:

<P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <L01>
    <A xsi:nil="true" />
    <B xsi:nil="true" />
    <C xsi:nil="true" />
  </L01>
  <L02>
    <A>2</A>
    <B xsi:nil="true" />
    <C>x</C>
  </L02>
</P>

示例:

declare
    @P xml;

declare
    @A varchar,
    @B varchar,
    @C varchar;

select
    @P = (
        select
            @A as [A],
            @B as [B],
            @C as [C]
        for xml path(N'L01'), root('P'), type, elements xsinil
        );

select @P; --Initial result

select
    @A = '2',
    @B = NULL,
    @C = 'x';

--select @P = ...?

select @P; --Final result

我做了以下事情:

select
    @P = (
        select (
            select
                v.query('.')
            from @P.nodes('P/L01') as t (v)),
            (
            select
                @A as [A],
                @B as [B],
                @C as [C]
            for xml path(N'L02'), type, elements xsinil
            )
        for xml path(N'P'), type, elements xsinil
        );

哪一个接近,但我不想在XML的开头/顶行以外的任何位置使用“ xmlns:xsi =“ http://www.w3.org/2001/XMLSchema-instance”“:< / p>

<P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <L01>
    <A xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
    <B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
    <C xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
  </L01>
  <L02 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <A>2</A>
    <B xsi:nil="true" />
    <C>x</C>
  </L02>
</P>

编辑(2018Dec14〜1343): 基于Schnugo的有用见解(是的,我需要/希望使用NULL值来记录所指示的元素,但未收到任何值。此外,我很抱歉,但我无法完全掌握所有内容1-5中提出的建议),我提出了以下建议:

select
    @P = (      
        select
            cast(replace(replace(cast(([XML].[Value]) as nvarchar(max)), cjR.Old01, cjR.New01), cjR.Old02, cjR.New02) as xml)
        from (
            select (
                select
                    v.query('.')
                from @P.nodes(N'P/L01') as t (v)),
                (
                select
                    @A as [A],
                    @B as [B],
                    @C as [C]
                for xml path(N'L02'), type, elements xsinil
                )
            for xml path(N'P'), type, elements xsinil
            ) as [XML] ([Value])
        cross join (
            select
                Value02 as Old01,
                N'' as New01,
                quotename(Value01, N'<>') as Old02,
                quotename(Value01 + Value02, N'<>') as New02
            from (
                select
                    N'P',
                    N' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
                ) as R (Value01, Value02)
            ) as cjR
        );

看起来像是一种骇人听闻的方式来产生应该如此简单的操作,但显然并非如此。我欢迎任何进一步的建议来改善这一点。

1 个答案:

答案 0 :(得分:0)

您在这里遇到了SQL Server XML支持的各种缺陷...

使用嵌套XML,便没有其他方法可以使用子查询。但是子查询中的重复命名空间是一个非常烦人的问题。生成的XML完全可以,但是重复的名称空间声明确实会极大地膨胀您的XML。讨论了几个世纪(并寻求更好的解决方案)。有十多年的Connect-Ticket,获得了很多票。但这与Connect一起消失了。

您真的需要NULL值来与xsi:nil一起炫耀吗?默认是省略它们...

很多时候您会看到丑陋的解决方法
它们全部使用CASTNVARCHAR(MAX),使用字符串方法(STUFFSUBSTRING,...)操纵名称空间,并在结束。

  1. 默认名称空间:创建不带名称空间的XML,并将顶部节点与名称空间一起添加
  2. 前缀命名空间:使用命名空间 placeholder 创建XML,然后再次使用字符串方法(REPLACE)纠正此问题(look at this answer
  3. 您的示例似乎需要xsi:nil来强制执行NULL值,以免被忽略。更糟的是...您可以在创建XML的同时创建XML,然后使用字符串方法来丢弃错误的声明。
  4. 您可以通过串联在字符串级别构建整个对象
  5. FOR XML EXPLICIT。这是一种奇怪且难以学习的格式。但这是我知道的唯一一种以所需的方式正确设置名称空间的方法。

对不起,但这正是XML SQL-Server无法轻松构建的类型...

如果您需要有关所提供选项之一的帮助,则可以在此问题上先提出一个具体问题。