我有一个关于使用SQL Server FOR XML来创建带有命名空间的XML文档的问题。我需要创建一个如下文档,其中根元素(xmlns:ijk="h:/i.j.k"
)中有一个名称空间定义,子元素属性(ijk:LMNO="3333"
)中有一个名称空间引用。
我正在生成XML以POST到Web服务:
<ROOT xmlns:ijk="h:/i.j.k" RSTU="1111">
<CHILD CDEF="2222" ijk:LMNO="3333" />
</ROOT>
在我开始使用命名空间之前,我编写了第一个示例查询以使结构正确,结果是预期的结果。
SELECT
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
结果
<ROOT RSTU="1111">
<CHILD CDEF="2222" LMNO="3333" />
</ROOT>
然后我尝试使用WITH NAMESPACES
添加命名空间,但SQL Server被带走并将所有命名空间添加到所有元素。目标Web服务不接受带有命名空间重载的XML(在我的实际情况中,有四个级别的元素和三个命名空间,它会造成一个真正的混乱)。
WITH XMLNAMESPACES ('h:/i.j.k' as ijk, 'h:/x.y.z' as xyz)
SELECT
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [ijk:LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
结果:
<ROOT xmlns:xyz="h:/x.y.z" xmlns:ijk="h:/i.j.k" RSTU="1111">
<CHILD xmlns:xyz="h:/x.y.z" xmlns:ijk="h:/i.j.k" CDEF="2222" ijk:LMNO="3333" />
</ROOT>
我在联机丛书中读到,虽然不推荐,但可以像常规属性一样添加名称空间。我尝试了这个,它生成了正确的命名空间定义:
SELECT
[xmlns:ijk] = 'h:/i.j.k',
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
结果:
<ROOT xmlns:ijk="h:/i.j.k" RSTU="1111">
<CHILD CDEF="2222" LMNO="3333" />
</ROOT>
上面的输出具有良好的命名空间定义,但LMNO属性没有必需的ijk:名称空间引用前缀。我尝试添加命名空间引用,但是我收到了一个错误:
SELECT
[xmlns:ijk] = 'h:/i.j.k',
[RSTU] = 1111,
(SELECT
[CDEF] = 2222, [ijk:LMNO] = 3333
FOR XML RAW('CHILD'), TYPE)
FOR XML RAW('ROOT'), TYPE;
结果:
Msg 6846,Level 16,State 2,Line 34
FOR XML列名'ijk:LMNO'缺少XML名称空间前缀'ijk'声明。
是否可以编写生成XML的T-SQL FOR XML查询,其中包括:
命名空间仅在根元素中定义,
根元素具有除命名空间定义以外的数据属性,
对命名空间的引用用于子元素中的属性名称?
我查看了How do I remove redundant namespace in nested query when using FOR XML PATH。在本主题中,根元素只有名称空间定义,没有数据属性。
答案 0 :(得分:1)
这很难看,但是解决方法
SELECT
CAST(REPLACE(CAST(
(SELECT
[xmlns:xyz] = 'h:/x.y.z',
[xmlns:ijk] = 'h:/i.j.k',
[RSTU] = 1111,
(SELECT
[@CDEF] = 2222, [@ns_ijk_LMNO] = 3333
FOR XML PATH('ROOT'), TYPE)
FOR XML RAW('CHILD'), TYPE) AS NVARCHAR(MAX)),'ns_ijk_','ijk:') AS XML);
结果
<CHILD xmlns:xyz="h:/x.y.z" xmlns:ijk="h:/i.j.k" RSTU="1111">
<ROOT CDEF="2222" ijk:LMNO="3333" />
</CHILD>
通过对RAW
使用SELECT
模式,允许将名称空间声明放置为属性。
内部FOR XML PATH
将不使用这些名称空间(WITH XMLNAMESPACES
的其他行为!),但不可能在那里使用名称空间前缀。
所以我在属性名称中添加了一些内容,将整个XML转换为NVARCHAR(MAX)
,替换我的假人并将其丢回。
请转到the connect issue并投票。这真烦人!
重复的命名空间(使用子选择时)没有错,但是输出膨胀并且可能在验证器中发生冲突。
答案 1 :(得分:0)
结果
<ROOT xmlns:xyz="h:/x.y.z" xmlns:ijk="h:/i.j.k" RSTU="1111">
<CHILD xmlns:xyz="h:/x.y.z" xmlns:ijk="h:/i.j.k" CDEF="2222" ijk:LMNO="3333" />
</ROOT>
看起来你有一个无关的xyz
命名空间,但其余的看似有效。定义命名空间与将命名空间应用于元素或属性不同,如果未应用定义的命名空间(即在LMNO
元素上预先添加),则可以忽略它们。两次定义命名空间是多余的,但不应该是无效的。
XML是一个挑剔的标准,所以也许可能真的是在验证中需要&#39;此
当然,没有改变你的问题,但是与验证者有着奇怪期望的方式相同,许多XML生成器不会在可选值上提供这种灵活性。他们经常拥有“这就是你得到的东西”。方法