简体   繁体   English

使用命名空间修改xml

[英]Modify xml with namespaces

I'm trying to modify predefined xml (xsd to be more specific) in TSQL. 我正在尝试在TSQL中修改预定义的xml(xsd更具体)。 I want to insert enumeration restriction to one of the xsd elements. 我想在其中一个xsd元素中插入枚举限制。

The task is to fill xsd restrictions based on a query example: 任务是根据查询示例填充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

The problem is that code outputs unnecessary xmlns attribute 问题是代码输出了不必要的xmlns属性

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

Can anyone help ? 有人可以帮忙吗?

It got a bit more ugly than I hoped. 它比我希望的更难看。 Mainly because I can't use sql:variable("@enumeration")/delete-me/node() inside a .modify() . 主要是因为我不能在.modify()使用sql:variable("@enumeration")/delete-me/node() .modify()

I assume, that you can modify the generation of the @enumeration , as follows: 我假设你可以修改@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
);

The idea is to use FOR XML with ROOT , so that the generated namespace is at the unnecessary root element (which can be skipped). 我们的想法是使用带有ROOT FOR XML ,以便生成的命名空间位于不必要的根元素(可以跳过)。 Otherwise we would have to recreate the xs:enumeration -elements later. 否则我们将不得不在以后重新创建xs:enumeration -elements。

Two solutions 两种解决方案

Use .modify() three times 使用.modify()三次

The idea: 想法:

  1. We insert everything from @enumeration (with the unnecessary root) somewhere into the other xml 我们将@enumeration (带有不必要的根)的所有内容插入到另一个xml中
  2. We copy the desired content to the right place 我们将所需内容复制到正确的位置
  3. We delete the no longer needed copy of @enumeration in @schema . 我们在@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() to create @schema .query()创建@schema

If you can change the part where @schema is created, you can generate @schema directly as .query() from @enumeration : 如果您可以更改创建@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;

You can do a simple string replace if the xml isn't too big: 如果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)

If your XML isn't too complicated, why not use FOR XML EXPLICIT instead? 如果您的XML不是太复杂,为什么不使用FOR XML EXPLICIT呢?

Another workaround would be to get generate the XML without the namespace and then add it in afterwards. 另一种解决方法是在没有命名空间的情况下生成XML,然后再添加它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM