可以xquery删除文本xmlns =""来自一个节点

时间:2017-07-14 15:53:13

标签: sql-server xml

操作系统:Windows 10

MS SQL版:SQL 2016

我已经广泛搜索了StackOverflow并发现了许多与我的非常相似的问题,但似乎没有一个问题与我的情况相符,或者有一个我有实施知识或技能的回复。我不知道如何在SQL中实现C#解决方案,也不知道如何使用样式表转换语言,所以这是我的问题。

我正在从表格创建XML文档,并且必须使其与我的客户的布局完全匹配。文档的外部结构如下所示:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ScreenResponse xmlns="http://schemas.myuri.com/CC/v1_4">
      <CustomerScreenResult>
       <ServiceCallID />
        <IsSuccessful>true</IsSuccessful>
        <CustomerScreenResponse>
          <IsSuccessful>true</IsSuccessful>
        </CustomerScreenResponse>
      </CustomerScreenResult>
    </ScreenResponse>
  </s:Body>
</s:Envelope>

上面的对象在我的存储过程中称为@xml_out,其数据类型为XML,并保持不变。请注意,它仅使用模式和名称空间而不使用样式表。接下来,我构建另一个XML文档,该文档仅显示客户需要查看的节点。它看起来像这样:

<SpecificScreenResults>
  <CaseScreenResult>
    <ScreenMessage>This is a sample screenmessage.</ScreenMessage>
  </CaseScreenResult>
  <CaseScreenResult>
    <ScreenMessage>This is another sample screenmessage.</ScreenMessage>
  </CaseScreenResult>
</SpecificScreenResults>

在SSMS中,我使用与此类似的代码创建该文档:

SET @xml_var1 = ( SELECT a.ScreenMessage
FROM #CustScrn a 
FOR
XML PATH('CaseScreenResult'),
ELEMENTS,
ROOT ('SpecificScreenResults'),
TYPE);

最后,我使用xquery insert语句将第二个XML对象(@ xml_var1)插入到第一个XML对象中。首先,这是我使用的SQL语句:

SET @xml_out.modify('declare default element namespace "http://schemas.myuri.com/CC/v1_4"; insert sql:variable ("@xml_var1") as first into (//CustomerScreenResponse)[1]');

这会产生以下XML对象:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ScreenResponse xmlns="http://schemas.myuri.com/CC/v1_4">
      <CustomerScreenResult>
        <ServiceCallID />
        <IsSuccessful>true</IsSuccessful>
        <CustomerScreenResponse>
          <SpecificScreenResults xmlns="">
            <CaseScreenResult>
              <ScreenMessage>This is a sample screenmessage.</ScreenMessage>
            </CaseScreenResult>
            <CaseScreenResult>
              <ScreenMessage>This is another sample creenmessage.</ScreenMessage>
            </CaseScreenResult>
          </SpecificScreenResults>
          <IsSuccessful>true</IsSuccessful>
        </CustomerScreenResponse>
      </CustomerScreenResult>
    </ScreenResponse>
  </s:Body>
</s:Envelope>

注意一个节点,SpecificScreenResults正在接收额外的xmlns =&#34;&#34;名称空间指示我认为这种情况正在发生,因为我插入的XML与命名空间没有关联,因此添加了一个空白的XML。我理解,从XML的角度来看,这个文本是微不足道的,但对我的客户而言,他们不想处理它是一种恼人。目前我处理问题的方法是将整个对象转换为VARCHAR(MAX),使用REPLACE()函数将其删除,然后将其转换回XML。这对于具有少量记录的结果是可行的,但是当表结果数字为数百万时,效果不太好。

是或否,是否有xquery delete命令我可以用来删除xmlns =&#34;&#34;从节点?有没有更好的方法来执行插入以防止空白发生?如果是这样,有人可以提供一个例子吗?

2 个答案:

答案 0 :(得分:0)

这个xmlns=""不仅令人烦恼,它还指出,内部节点不在你上面​​声明的默认命名空间内!这很可能,实际上不是你想要的...

您可以创建要插入的节点,包括WITH XMLNAMESPACES(...)。这将在与外部节点相同的默认命名空间内创建新节点。通过.modify()插入后,您会注意到,您会多次找到xmlns="..."。这没有错,只是烦人和膨胀你的XML ...

这是一个持久的问题。看到这个Connect article!请登录并投票!

有几种方法可以使用字符串方法。丑陋但工作......

  

目前我处理问题的方法是将整个对象转换为VARCHAR(MAX),使用REPLACE()函数将其删除,然后将其转换回XML。

这没关系,但您应该使用NVARCHAR。使用VARCHAR可能会让您在使用非普通拉丁字符时陷入困境......

大多数人会建议在没有任何名称空间的情况下创建XML,并使用STUFF在字符串级别插入所有名称空间。

答案 1 :(得分:0)

  

据我所知,从XML的角度来看,这个文字是微不足道的,   但对我的客户而言,他们不想要处理这是一种恼怒   用。

相反,这个小小的声明非常重要。

您在无命名空间中创建了<SpecificScreenResults>元素及其后代。当您将其复制为另一个文档的子树时,它将保留在无命名空间中,并添加xmlns=""声明以反映此事实。

您似乎希望<SpecificScreenResults>元素位于命名空间"http://schemas.myuri.com/CC/v1_4"中。如果要在该命名空间中使用它,则必须在该命名空间中创建它,或者随后对其进行转换以更改其命名空间。

重要的是要记住,元素的名称是(命名空间,本地名称)对,复制元素时,其名称保持不变。像xmlns=""这样的命名空间声明不是XPath / XQuery数据模型的一部分,它们是词法(序列化)XML的工件,旨在确保在将树转换为词法XML然后将其解析回树时,元素的名称保持不变。如果一个元素是一个名称空间而其父元素位于不同的名称空间中,那么在序列化时,将添加名称空间声明以反映这一事实。