【问题标题】:Adding a child element to an element in another namespace with XML schema使用 XML 模式将子元素添加到另一个命名空间中的元素
【发布时间】:2021-01-04 08:09:46
【问题描述】:

我在某个命名空间中有一个用于某个 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 的超集,它只是看起来像一个。

【问题讨论】:

  • 您可以简单地导入包含新子元素的 XSD,并将可选元素引用添加到复杂类型 B。您考虑过这种方法并拒绝了吗?
  • 您能否详细说明“导入...并添加可选元素引用”的含义?你的意思是,修改原来的 XSD 模式定义?目标是获取一个符合 schema1(仅!)的输入文档,然后返回它扩展了由 schema2 定义的元素。我想让我的最终用户针对不同的模式验证输入文档和扩展返回文档,所以我需要发布这两个模式。我也会将该信息添加到问题中。
  • @kimbert 我已经添加了更多关于实际目标和我们当前解决该问题的方法的信息。也许这就是你要问的。

标签: xml xsd


【解决方案1】:

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

<?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>

【讨论】:

  • 这是一个有趣的想法——定义一个新的环绕元素,重用和扩展子元素。但是,真正的架构定义非常复杂,并且包含很大的元素层次结构,我需要在叶级别添加一个子元素。 (即,在我上面的示例中,想象在 ab 之间有很多东西。)使用这种技术,我需要在新的架构和命名空间中复制所有这些,对吧?
【解决方案2】:

这不是一个答案...只是寻求进一步的澄清,以了解您要完成的工作。

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

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

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

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

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

【讨论】:

  • “不清楚(对我来说,无论如何)为什么您的用户需要重新验证扩展文档。”他们不需要,只是应该能够。这只是另一种表达方式:输出文档应符合定义的模式。
  • 除此之外,感谢您提供指向文档的指针。我一直无法找到一个可以解决我的特定问题的概念,而无需其中一个架构复制大量其他架构定义的内容。但是,我不是专家,这就是我问这个问题的原因。
  • 可能是我对输出文档应该是什么样子的特定想法与 XML Schema 的功能不够一致。 (例如,如果我将s2:c 放在原始层次结构之外,只是以某种方式引用b 而不是嵌套在它下面,那么问题将很容易解决。不幸的是,它会使人类读者对文档的解释变得非常困难更难。)不过,在我放弃之前,我想听专家说“我做错了”。
  • 感谢您的澄清。我认为答案取决于您的应用程序在做什么,但我认为 StackOverflow 不适合这样做(除非您能想出一种方法来简单明了地表达您的所有要求)
猜你喜欢
  • 1970-01-01
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 2017-11-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多