微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 XML 模式将子元素添加到另一个命名空间中的元素

如何解决使用 XML 模式将子元素添加到另一个命名空间中的元素

对于特定命名空间中的特定 XML 架构,我有一个 XSD,我们称之为 http://mydomain/schema1。下面是一个相应的 XML 文件的示例:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="http://mydomain/schema1">
  <a>
    <b />
  </a>
</root>

现在,我想定义一个新模式,我们称之为 http://mydomain/schema2,它扩展一个,允许我在现有元素中放置新元素,像这样:

<root xmlns="http://mydomain/schema1" xmlns:s2="http://mydomain/schema2">
  <a>
    <b>
     <s2:c>...</s2:c>
    </b>
  </a>
</root>

这可以使用 XML 模式吗?给定 http://mydomain/schema1 的以下 XSD,http://mydomain/schema2 的 XSD 是什么样的,它会如何修改 B 的复杂类型定义?

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="schema1"
           targetNamespace="http://mydomain/schema1"
           elementFormDefault="qualified"
           xmlns="http://mydomain/schema1"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="root" type="Root" />

  <xs:complexType name="Root">
    <xs:sequence>
      <xs:element name="a" type="A" />
      <!-- ... -->
    </xs:sequence>
  </xs:complexType>
  
  <xs:complexType name="A">
    <xs:sequence>
      <xs:element name="b" type="B" />
      <!-- ... -->
    </xs:sequence>
  </xs:complexType>
  
  <xs:complexType name="B">
    <xs:sequence>
      <!-- ... -->
    </xs:sequence>
  </xs:complexType>
</xs:schema>

实际目标是获取一个符合 http://mydomain/schema1(仅!)的输入文档,然后返回它扩展了由 http://mydomain/schema2 定义的元素。我想让我的最终用户根据各自的架构定义验证输入文档和扩展返回文档,因此我需要发布这两个架构。

我们当前的解决方法是解析原始 XSD,修改架构定义以包含其他元素,然后将所有命名空间更新为 http://mydomain/schema2 并发布生成的架构。结果看起来像是 http://mydomain/schema1 的超集,但实际上为所有元素定义了不同的命名空间,即使是那些已经存在于 http://mydomain/schema1 中的元素。当我们获取实际的输入 XML 时,我们首先重写命名空间,然后添加新元素。这有效,但感觉有点笨拙 - 当然,http://mydomain/schema2 不是真的 http://mydomain/schema1 的超集,它只是看起来像一个

解决方法

您可以使用复杂类型中的扩展部分向复杂类型添加新元素。像这样:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns="http://tempuri.org/Childs" targetNamespace="http://tempuri.org/Childs">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Child" type="ChildType" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="ChildType">
        <xs:sequence>
            <xs:element type="xs:string" name="Name"/>
            <xs:element type="xs:date" name="DayOfBirth"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

这个 childs.xsd xml 模式文件将创建下面的 xml

<root xsi:schemaLocation="http://tempuri.org/Childs childs.xsd" xmlns="http://tempuri.org/Childs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Child>
        <Name>String</Name>
        <DayOfBirth>1967-08-13</DayOfBirth>
    </Child>
    <Child>
        <Name>String</Name>
        <DayOfBirth>1967-08-13</DayOfBirth>
    </Child>
</root>

现在在 parent.xsd 文件中导入 childs.xsd,因此可以使用该模式中的复杂类型。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/Parents" xmlns:c="http://tempuri.org/Childs" targetNamespace="http://tempuri.org/Parents" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:import namespace="http://tempuri.org/Childs" schemaLocation="Childs.xsd"/>
    <xs:element name="Root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Parent">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Childs" type="ChildType" maxOccurs="4"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="ChildType">
        <xs:complexContent>
            <xs:extension base="c:ChildType">
                <xs:sequence>
                    <xs:element name="Gender" type="xs:string"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
</xs:schema>

因为 parent.xsd 中的复杂类型 ChildType 使用 Childs.xsd 中的复杂 ChildType(因此需要使用命名空间前缀)作为基础,它将具有元素 Name 和 DayOfBirth。扩展部分可用于在基础内容下方添加内容。就像在这个例子中一样,已经添加了性别。

parent.xsd 的示例 xml 是:

<Root xsi:schemaLocation="http://tempuri.org/Parents parents.xsd" xmlns="http://tempuri.org/Parents" xmlns:c="http://tempuri.org/Childs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Parent>
        <Childs>
            <c:Name>String</c:Name>
            <c:DayOfBirth>1967-08-13</c:DayOfBirth>
            <Gender>String</Gender>
        </Childs>
        <Childs>
            <c:Name>String</c:Name>
            <c:DayOfBirth>1967-08-13</c:DayOfBirth>
            <Gender>String</Gender>
        </Childs>
    </Parent>
</Root>
,

这不是一个答案......只是寻求进一步的澄清以了解您正在努力实现的目标。

我想让我的最终用户根据各自的架构定义验证输入文档和扩展返回文档,因此我需要发布这两个架构。

不清楚(对我来说,无论如何)为什么您的用户需要重新验证扩展文档。如果您的程序运行正常,那么它肯定会生成符合新 XSD 的 XML 文档吗?

当我们获取实际的输入 XML 时,我们首先重写命名空间,然后添加新元素。可行,但感觉有点笨拙

比较两个 XSD 以确定新元素需要去哪里是一项非常重要的任务,除非您可以依靠 XSD 非常简单。同样适用于自动添加新元素。我希望您对 XSD 的设计进行强有力的管理,以防止它们变得复杂。

XML Schema 规范提供了许多不同的方法来更改和扩展复杂的类型定义。我不太了解您的要求,无法推荐解决方案,但我建议您阅读XML Schema Primer。它的可读性很强,可能会提供您尚未考虑过的新选项。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。