如何在没有命名空间累积的情况下将多个XML文档合并为一个?

时间:2017-07-07 12:19:39

标签: sql sql-server xml tsql xml-namespaces

我在一个存储为xml-document的表中有几个SVG段。 现在我需要从该表中选择所有元素,并将它们合并到一个XML文档中。

这是我的T-SQL代码:

import axios from 'axios'

export default async function getRequestedData (requestAddress, params) {
   return await axios.get(requestAddress, {params: params})
}

但这会产生

declare @xml table (xmldocument xml)
insert @xml select '
<svg xmlns="http://www.w3.org/2000/svg" otherattrib="x">
  <path id="789" data-objid="0000X2"></path>
</svg>'

insert @xml select '
<svg xmlns="http://www.w3.org/2000/svg" otherattrib="x">
  <admin>
  <g>
  <path></path>
  <path data-objid="0000X1"></path>
  <path id="123" data-objid="0000X2"></path>
  <path id="456" data-objid="0000X3"></path>
  </g>
  </admin>

    <g>
    <path></path>
    <path data-objid="0000X1"></path>
  <path id="789" data-objid="0000X2"></path>
  <path id="abc" data-objid="0000X3"></path>
  </g>
</svg>'


insert @xml select '
<svg xmlns="http://www.w3.org/2000/svg" otherattrib="x">
    <path></path>
</svg>'


insert @xml select '
<svg xmlns="http://www.w3.org/2000/svg" otherattrib="x">
  <path id="abc" data-objid="0000X3"></path>
</svg>'




--;WITH XMLNAMESPACES ('http://www.w3.org/2000/svg' AS svg)
;WITH XMLNAMESPACES (default 'http://www.w3.org/2000/svg')
--SELECT 
    --(
        SELECT 
             --xmldocument 

            --,c.p.value('.', 'nvarchar(MAX)')
            c.p.query('declare default element namespace "http://www.w3.org/2000/svg";.') 
        FROM @xml AS t

        OUTER APPLY t.xmldocument.nodes('/svg//*') AS c(p)

        FOR XML PATH(''), root('svg')
--  ) AS merged

而不是

<svg xmlns="http://www.w3.org/2000/svg">
  <path xmlns="http://www.w3.org/2000/svg" id="789" data-objid="0000X2" />
  <admin xmlns="http://www.w3.org/2000/svg">
    <g>
      <path />
      <path data-objid="0000X1" />
      <path id="123" data-objid="0000X2" />
      <path id="456" data-objid="0000X3" />
    </g>
  </admin>
  <g xmlns="http://www.w3.org/2000/svg">
    <path />
    <path data-objid="0000X1" />
    <path id="123" data-objid="0000X2" />
    <path id="456" data-objid="0000X3" />
  </g>
  <path xmlns="http://www.w3.org/2000/svg" />
  <path xmlns="http://www.w3.org/2000/svg" data-objid="0000X1" />
  <path xmlns="http://www.w3.org/2000/svg" id="123" data-objid="0000X2" />
  <path xmlns="http://www.w3.org/2000/svg" id="456" data-objid="0000X3" />
  <g xmlns="http://www.w3.org/2000/svg">
    <path />
    <path data-objid="0000X1" />
    <path id="789" data-objid="0000X2" />
    <path id="abc" data-objid="0000X3" />
  </g>
  <path xmlns="http://www.w3.org/2000/svg" />
  <path xmlns="http://www.w3.org/2000/svg" data-objid="0000X1" />
  <path xmlns="http://www.w3.org/2000/svg" id="789" data-objid="0000X2" />
  <path xmlns="http://www.w3.org/2000/svg" id="abc" data-objid="0000X3" />
  <path xmlns="http://www.w3.org/2000/svg" />
  <path xmlns="http://www.w3.org/2000/svg" id="abc" data-objid="0000X3" />
</svg>

我错过了什么?我做错了什么?
如何纠正这一点,而不必转换为varchar,然后对&#34; xmlns = ...&#34;进行搜索和替换。 ?

1 个答案:

答案 0 :(得分:0)

首先:重复的命名空间在任何方面都没有错,只是让你的结果变得烦人和膨胀......

不幸的是,没有办法以干净的方式摆脱它们。如果你真的需要这个,那么你想要转换为文本并在字符串级别执行此操作并不是那么糟糕(但请注意,该转换必须转到 N VARCHAR并且重新转换为XML可以更改你的XML结构(属性顺序,CDATA - 部分......)。试试这个:

简短方法

...如果你真的不需要其他任何东西,而不是第一个根<svg>中的命名空间......

DECLARE @NewXML NVARCHAR(MAX)=
(
    SELECT t.xmldocument.query('declare default element namespace "http://www.w3.org/2000/svg";svg/*')
    FROM @xml AS t
    FOR XML PATH('')
);
SELECT CAST(N'<svg xmlns="http://www.w3.org/2000/svg">' 
          + REPLACE(@NewXML,' xmlns="http://www.w3.org/2000/svg"','') 
          + N'</svg>' AS XML);

更灵活的方法

你可以试试这个:

DECLARE @NewXML XML=
(
    SELECT t.xmldocument.query('declare default element namespace "http://www.w3.org/2000/svg";svg/*')
    FROM @xml AS t
    FOR XML PATH(''),TYPE
);
SET @NewXML =CAST(REPLACE(CAST(@NewXML AS NVARCHAR(MAX)),' xmlns="http://www.w3.org/2000/svg"','') AS XML);

- 你需要重复CASTREPLACE,否则你会得到很多xmlns=""为内部节点定义一个空的默认命名空间,这是错误的...

WITH XMLNAMESPACES (DEFAULT 'http://www.w3.org/2000/svg')
SELECT @NewXML=CAST(REPLACE(CAST((SELECT @NewXML FOR XML PATH('svg'),TYPE) AS NVARCHAR(MAX)),' xmlns=""','') AS XML);
SELECT @NewXML;

您可以使用STUFF()在字符串级别引入命名空间:

(不要在这里使用WITH XMLNAMESPACES ......

SELECT @NewXML=CAST(STUFF(CAST((SELECT @NewXML FOR XML PATH('svg'),TYPE) AS NVARCHAR(MAX)),5,0,' xmlns="http://www.w3.org/2000/svg" ') AS XML);
SELECT @NewXML;

所有情况下的结果

<svg xmlns="http://www.w3.org/2000/svg">
  <path id="789" data-objid="0000X2" />
  <admin>
    <g>
      <path />
      <path data-objid="0000X1" />
      <path id="123" data-objid="0000X2" />
      <path id="456" data-objid="0000X3" />
    </g>
  </admin>
  <g>
    <path />
    <path data-objid="0000X1" />
    <path id="789" data-objid="0000X2" />
    <path id="abc" data-objid="0000X3" />
  </g>
  <path />
  <path id="abc" data-objid="0000X3" />
</svg>
相关问题