使用命名空间修改xml

18

我正在尝试在TSQL中修改预定义的xml(更具体地说是xsd)。 我想要向其中一个xsd元素插入枚举限制。

任务是基于查询填充xsd限制 例如:

create table #list(value nvarchar(100))
insert into #list values('item 1')
insert into #list values('item 2')
insert into #list values('item 3')
insert into #list values('item 4')
insert into #list values('item 5')
insert into #list values('item 6')

declare @enumeration as xml
;with xmlnamespaces('http://www.w3.org/2001/XMLSchema' as xs)
select @enumeration = (
    select value as '@value'
    from #list for xml path('xs:enumeration')
)

declare @schema xml
set @schema =
'<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="test">
    <xs:element name="test" msdata:IsDataSet="true" msdata:MainDataTable="Example" msdata:UseCurrentLocale="true">
        <xs:complexType>
            <xs:choice maxOccurs="unbounded">
                <xs:element name="Example">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="myList" minOccurs="1" nillable="false">
                                <xs:simpleType>
                                    <xs:restriction base="xs:string">
                                        <xs:maxLength value="50" />
                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:choice>
        </xs:complexType>
    </xs:element>
</xs:schema>'

set @schema.modify
    ('insert sql:variable("@enumeration")
    into (//xs:element[@name=''myList'']/xs:simpleType/xs:restriction)[1]')

select @schema

问题在于代码输出了不必要的xmlns属性

<xs:enumeration xmlns:xs="http://www.w3.org/2001/XMLSchema" value="item 1" />

有人可以帮忙吗?


3
祝你好运。记住:培养自己适应不必要但无害的命名空间声明通常比让系统停止发出它们更快。 - C. M. Sperberg-McQueen
3
虽然不完全符合你的情况,但你可以在这里找到答案:链接。换句话说,如果你无法忽略它,并且将xml->nvarchar(max)->replace->xml转换不够优雅,你总是可以编写一个CLR ;) - OzrenTkalcecKrznaric
1
@tr3,真正的问题是你能发音他的名字吗? - Alex Gordon
已经过去了10年,没有任何行动,但也许再多一些投票最终会给我们一个真正的解决方案,而不是人们一直试图找到的解决方法:http://connect.microsoft.com/SQLServer/feedback/details/265956/suppress-namespace-attributes-in-nested-select-for-xml-statements - bielawski
显示剩余2条评论
3个回答

2

情况比我预期的更加棘手了。主要是因为我无法在.modify()中使用sql:variable("@enumeration")/delete-me/node()

我认为,您可以按照以下方式修改@enumeration的生成:

CREATE TABLE #list (value nvarchar(100));
INSERT  INTO #list
VALUES  ('item 1');
INSERT  INTO #list
VALUES  ('item 2');
INSERT  INTO #list
VALUES  ('item 3');
INSERT  INTO #list
VALUES  ('item 4');
INSERT  INTO #list
VALUES  ('item 5');
INSERT  INTO #list
VALUES  ('item 6');

DECLARE @enumeration AS xml;
WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema' AS xs)
SELECT @enumeration = (
    SELECT value AS '@value'
    FROM #list FOR XML PATH('xs:enumeration'), ROOT('delete-me'), TYPE
);

这个想法是使用FOR XMLROOT,这样生成的命名空间就在不必要的根元素中(可以跳过)。否则,我们以后将不得不重新创建xs:enumeration元素。

两种解决方案

使用.modify()三次

思路:

  1. 我们将来自@enumeration(带有不必要的根)的所有内容插入到其他xml中的某个位置
  2. 我们将所需内容复制到正确的位置
  3. 我们删除@schema中不再需要的@enumeration副本。
DECLARE @schema xml;
SET @schema = '<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="test">
    <xs:element name="test" msdata:IsDataSet="true" msdata:MainDataTable="Example" msdata:UseCurrentLocale="true">
        <xs:complexType>
            <xs:choice maxOccurs="unbounded">
                <xs:element name="Example">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="myList" minOccurs="1" nillable="false">
                                <xs:simpleType>
                                    <xs:restriction base="xs:string">
                                        <xs:maxLength value="50" />
                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:choice>
        </xs:complexType>
    </xs:element>
</xs:schema>';

SET @schema.modify('insert sql:variable("@enumeration")
    into /');

SET @schema.modify('declare namespace xs="http://www.w3.org/2001/XMLSchema";
insert /delete-me/node()
    into (//xs:element[@name=''myList'']/xs:simpleType/xs:restriction)[1]');

SET @schema.modify('delete /delete-me');

SELECT  @schema;

DROP TABLE #list;

.query() 用于创建 @schema

如果您可以更改创建 @schema 的部分,您可以直接从 @enumeration 中生成 @schema,方法是使用 .query()

DECLARE @enumeration AS xml;
WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema' AS xs)
SELECT @enumeration = (
    SELECT value AS '@value'
    FROM #list FOR XML PATH('xs:enumeration'), ROOT('delete-me'), TYPE
);

DECLARE @schema xml;
SET @schema = @enumeration.query('<xs:schema xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="test">
    <xs:element name="test" msdata:IsDataSet="true" msdata:MainDataTable="Example" msdata:UseCurrentLocale="true">
        <xs:complexType>
            <xs:choice maxOccurs="unbounded">
                <xs:element name="Example">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="myList" minOccurs="1" nillable="false">
                                <xs:simpleType>
                                    <xs:restriction base="xs:string">
                                        <xs:maxLength value="50" />
                                        {/delete-me/node()}
                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:choice>
        </xs:complexType>
    </xs:element>
</xs:schema>');

SELECT  @schema;

0

如果 XML 不太大,您可以进行简单的字符串替换:

DECLARE @schemaVARCHAR (MAX)
SET @schemaVARCHAR = CAST(@schema AS VARCHAR(MAX))
SET @schemaVARCHAR = 
    REPLACE(
        @schemaVARCHAR, 
        '<xs:enumeration xmlns:xs="http://www.w3.org/2001/XMLSchema" value="item 1" />',
        ''
    )

SET @schema = CAST(@schemaVARCHAR AS XML)

然后将其放入REPLACE函数中。我的只是一个例子。如果您需要删除/更改多个内容,您也可以重复执行此操作。 - Russell Fox
重点是你不应该像编辑文本一样编辑XML。前缀并不重要。 - John Saunders
@JohnSaunders 我不同意你的看法 - 这个回答是有价值的。如果在这种非常特殊的情况下创建的完全无害的 XML 代码膨胀对 OP 来说是完全不能接受的,那么进行字符串替换操作是有必要的,以维护理智的利益。我完全赞同你将 XML 视为文本是邪恶的观点。 - tom redfern
@hugh:你刚刚证明了它没有价值的原因:将XML视为文本是邪恶的。为了更清楚地说明,如果为每个元素使用不同的前缀会怎样? - John Saunders

0
如果你的 XML 不太复杂,为什么不使用 FOR XML EXPLICIT 呢?
另一个解决方法是先生成没有命名空间的 XML,然后再在之后添加上它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接