我在存储为 xml 文档的表中有几个 SVG 段。 现在我需要从该表中选择所有元素,并将它们合并到一个 XML 文档中。
这是我的 T-SQL 代码:
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>
代替
<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="123" data-objid="0000X2" />
<path id="456" data-objid="0000X3" />
</g>
<path />
<path data-objid="0000X1" />
<path id="123" data-objid="0000X2" />
<path id="456" data-objid="0000X3" />
<g>
<path />
<path data-objid="0000X1" />
<path id="789" data-objid="0000X2" />
<path id="abc" data-objid="0000X3" />
</g>
<path />
<path data-objid="0000X1" />
<path id="789" data-objid="0000X2" />
<path id="abc" data-objid="0000X3" />
<path />
<path id="abc" data-objid="0000X3" />
</svg>
我错过了什么?我做错了什么?
如何在不必强制转换为 varchar 的情况下更正此问题,然后在 "xmlns=..."上进行搜索和替换?
最佳答案
首先:重复的命名空间在任何方面都没有错,只是烦人和膨胀了结果的大小......
不幸的是,没有办法以干净的方式摆脱它们。如果您真的需要这个,您将转换为文本并在字符串级别执行此操作的想法还不错(但请注意,转换必须转到 NVARCHAR 并且重新转换为 XML 可能会改变您的 XML 结构(属性顺序,CDATA
-sections...)。试试这个:
短方法
...如果您真的不需要任何其他东西,除了第一个根 <svg>
中的 namespace ...
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);
--你需要重复 CAST
和 REPLACE
,否则你会得到很多 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>
关于sql - 如何在没有 namespace 积累的情况下将多个 XML 文档合并为一个文档?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44970598/