【问题标题】:Modify xml with namespaces使用命名空间修改 xml
【发布时间】:2012-10-10 00:50:57
【问题描述】:

我正在尝试在 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" />

谁能帮忙?

【问题讨论】:

  • 祝你好运。请记住:训练自己接受不必要但无害的命名空间声明通常比让系统停止发出它们要快。
  • 不完全是你的情况,但你可以找到答案here。换句话说:如果你不能忽略它并且 xml->nvarchar(max)->replace->xml 不够优雅,你总是可以写一个 CLR ;)
  • 我同意 Ozren Tkalčec Krznarić 关于 CLR 的看法
  • @tr3 真正的问题是你能说出他的名字吗
  • @АртёмЦарионов 完美吗?不是,但也许我可以:) 我大部分时间都在斯拉夫人口附近度过,也许我可以正确地发音他的名字:P

标签: sql sql-server xml tsql xsd


【解决方案1】:

它比我希望的要丑一些。主要是因为我不能在.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() 3 次

想法:

  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;

【讨论】:

    【解决方案2】:

    如果 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 函数中。我的只是一个例子。如果您需要删除/更改多项内容,也可以重复执行此操作。
    • 重点是您不应该像编辑文本那样编辑 XML。前缀无关紧要。
    • @JohnSaunders 我不同意 - 答案是有道理的。如果在这个非常具体的实例中创建的完全无害的 xml 膨胀对于 OP 来说是完全不可接受的,那么出于理智的考虑,有必要进行字符串替换操作。我完全同意你的观点,将 xml 视为文本是邪恶的。
    • @hugh:您刚刚说明了为什么它没有优点:将 XML 视为文本是邪恶的。更清楚地说:如果为每个元素使用不同的前缀会怎样?
    【解决方案3】:

    如果您的 XML 不是太复杂,为什么不使用 FOR XML EXPLICIT 来代替?

    另一种解决方法是生成没有命名空间的 XML,然后添加它。

    【讨论】:

      猜你喜欢
      • 2012-04-02
      • 2021-02-16
      • 1970-01-01
      • 2014-01-23
      • 1970-01-01
      • 2011-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多