如何在不对选择进行排序的情况下扩展选择 complexType?

How to extend a choice complexType without sequencing the choice?

提问人:ceving 提问时间:1/26/2012 更新时间:4/24/2020 访问量:18693

问:

我有一个选择complexType,名为:abType

<xs:complexType name="abType">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="a"/>
        <xs:element name="b"/>
    </xs:choice>
</xs:complexType>

此类型可用于按以下任意顺序创建带有 和 节点的元素,例如:ab

<ab>
    <b/>
    <a/>
</ab>

现在我想创建一个派生类型,称为允许节点,并且按任何顺序。因此,我根据以下条件创建了一个新的complexType:abcTypeabcabType

<xs:complexType name="abcType">
    <xs:complexContent>
        <xs:extension base="abType">
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element name="c"/>
            </xs:choice>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

之后,我创建了一个节点:abc

<abc>
    <c/>
    <b/>
    <a/>
</abc>

但是这个节点是无效的!将 any 或 放在 .原因是,从基类型派生类型会创建一个隐式序列,尽管这两种类型都是选择。XMLspy 是这样说明的:abc

Extended Choice Type

这个结果对于选择类型是相当无用的。

所以我的问题是:如何在不对选择进行排序的情况下扩展选择类型?

下面是完整的 XSD 和用于重现该问题的 XML 测试文件:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="root">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="ab"/>
            <xs:element ref="abc"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
<xs:element name="ab" type="abType"/>
<xs:complexType name="abType">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="a"/>
        <xs:element name="b"/>
    </xs:choice>
</xs:complexType>
<xs:element name="abc" type="abcType"/>
<xs:complexType name="abcType">
    <xs:complexContent>
        <xs:extension base="abType">
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element name="c"/>
            </xs:choice>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>
</xs:schema>

例:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="inherit-choice.xsd">
<ab>
    <b/>
    <a/>
</ab>
<abc>
    <c/>
    <b/>
    <a/>
</abc>
</root>
XSD的

评论


答:

12赞 Petru Gardea 1/26/2012 #1

不幸的是,简短的回答是否定的,你不能扩展选择合成器。从逻辑上讲,如果 a、b 和 c 之间存在某种关系(如在 Java、.NET 中,所有东西最终都是一个对象,您可以在 XSD 中执行相同的操作),那么我建议改用替换组(或者,如果您愿意,可以基于 xsi:type 的东西)。

UPDATE 举例说明。The XSD-1:

<?xml version="1.0" encoding="utf-8" ?>
<!--W3C Schema generated by QTAssistant/W3C Schema Refactoring Module (http://www.paschidev.com)-->
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:element name="ab" type="abType"/>

    <xsd:complexType name="abType">
        <xsd:sequence>
            <xsd:element ref="ExtensibleChoice-A" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:element name="ExtensibleChoice-A" type="ExtensibleChoiceBaseType" abstract="true" />

    <xsd:complexType name="ExtensibleChoiceBaseType" abstract="true">
        <xsd:sequence/>
    </xsd:complexType>

    <xsd:element name="a" substitutionGroup="ExtensibleChoice-A" type="aType" block="#all"/>
    <xsd:element name="b" substitutionGroup="ExtensibleChoice-A" type="bType" block="#all"/>
    <xsd:element name="c" substitutionGroup="ExtensibleChoice-A" type="cType" block="#all"/>

    <xsd:complexType name="aType">
        <xsd:complexContent>
            <xsd:extension base="ExtensibleChoiceBaseType">
                <xsd:sequence>
                    <xsd:element name="aChild" type="xsd:string"/>
                </xsd:sequence>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:complexType name="bType">
        <xsd:complexContent>
            <xsd:extension base="ExtensibleChoiceBaseType">
                <xsd:sequence>
                    <xsd:element name="bChild" type="xsd:int"/>
                </xsd:sequence>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:complexType name="cType">
        <xsd:complexContent>
            <xsd:extension base="ExtensibleChoiceBaseType">
                <xsd:sequence>
                    <xsd:element name="cChild" type="xsd:string"/>
                </xsd:sequence>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:schema>

Members of the substitution group

可扩展性是,在某个时间点,您可能只有 abc 作为成员。如果您或使用者决定添加某些内容(例如 d 元素),则只需使用新元素 d 创建另一个引用旧架构的架构,然后改用该新架构。旧的 XSD 文件不会被触及;生成新的 JAXB 类(例如)将导致向后兼容的代码。

因此,XSD-1 将验证如下内容:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<ab xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
    <a>
        <aChild>aChild1</aChild>
    </a>
    <b>
        <bChild>1</bChild>
    </b>
    <c>
        <cChild>cChild1</cChild>
    </c>
</ab>

Sample XML for XSD-1

您将需要这样的东西 (XSD-2):

<?xml version="1.0" encoding="utf-8" ?>
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema1.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema1.xsd" xmlns:b="http://tempuri.org/XMLSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:import namespace="http://tempuri.org/XMLSchema.xsd" schemaLocation="XSD-1.xsd"/>

    <xsd:element name="d" substitutionGroup="b:ExtensibleChoice-A" type="dType" block="#all"/>

    <xsd:complexType name="dType">
        <xsd:complexContent>
            <xsd:extension base="b:ExtensibleChoiceBaseType">
                <xsd:sequence>
                    <xsd:element name="dChild" type="xsd:string"/>
                </xsd:sequence>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:schema>
  • 该图显示了“新”成员列表,D 以蓝色突出显示:

Extended substitution group members list

要验证这一点,请执行以下操作:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<ab xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:d="http://tempuri.org/XMLSchema1.xsd">
    <a>
        <aChild>aChild1</aChild>
    </a>
    <d:d>
        <d:dChild>1</d:dChild>
    </d:d>
</ab>

Sample XML showing the new member

评论

0赞 ceving 1/26/2012
如何使用替换组实现继承?
0赞 brabec 4/7/2015
您能解释一下为什么使用替换阻止吗?
1赞 Petru Gardea 4/9/2015
@prasopes,在这种情况下没有特别的原因。一般来说,这取决于你想做什么。如果您有兴趣了解它是否适用于您的情况,请查看它的含义(例如此处)。
1赞 user47900 1/26/2012 #2

另一个例子是替换。

XSD型

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="abExtension"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="abExtension" type="abExtensionType"/>
    <xs:complexType name="abExtensionType">
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="a"/>
            <xs:element name="b"/>
        </xs:choice>
    </xs:complexType>
    <xs:element name="abcExtension" substitutionGroup="abExtension">
        <xs:complexType>
            <xs:complexContent>
                <xs:extension base="abExtensionType">
                    <xs:choice minOccurs="0" maxOccurs="unbounded">
                        <xs:element name="c"/>
                    </xs:choice>
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    </xs:element>
    <xs:element name="abcdExtension" substitutionGroup="abExtension">
        <xs:complexType>
            <xs:complexContent>
                <xs:extension base="abExtensionType">
                    <xs:choice minOccurs="0" maxOccurs="unbounded">
                        <xs:element name="c"/>
                        <xs:element name="d"/>
                    </xs:choice>
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    </xs:element>
</xs:schema>

使用此验证的示例 XML 是

abc扩展.xml

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test.xsd">
    <abcExtension>
        <b></b>
        <a></a>
        <c></c>
    </abcExtension>
</root>

wen dang扩展.xml

  <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test.xsd">
<abcdExtension>
        <a>text</a>
        <b>test</b>
        <d>text</d>
        <c>text</c>
    </abcdExtension>
</root>

abExtension.xml

     <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test.xsd">
<abExtension>
        <b></b>
        <a></a> 
    </abExtension>
</root>

评论

0赞 Petru Gardea 1/26/2012
您的回答不满足请求。您缺少需要验证 c - b - a 的方案(请参阅 <abc/> 示例)。通过使用选择扩展元素,您可以创建“隔间”;最终结果不是一个真正的选择,扩展类型中的内容可以先于基本类型中的内容显示......
0赞 user47900 1/26/2012
@PetruGardea同意。我只是举了一个例子,因为 OP 询问如何在设计中使用替换组。
17赞 Sean Ellis 1/6/2015 #3

有一种方法可以做到这一点,它依赖于这样一个事实,即选择中的选择充当更大的选择。

首先,定义一个元素组,该元素组包含基本元素中所有元素中的单个选项:

<xs:group name="common_ab_elements">
    <xs:choice>
        <xs:element name="a"/>
        <xs:element name="b"/>
    </xs:choice>
</xs:group>

然后,您可以在 abElement 的定义中使用它来代替之前使用的元素:

<xs:complexType name="abType">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:group ref="common_ab_elements"/>
    </xs:choice>
</xs:complexType>

如果需要扩展类型,则可以扩展选择:

<xs:complexType name="abcType">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:group ref="common_ab_elements"/>
        <xs:element name="c"/>
    </xs:choice>
</xs:complexType>

这相当于:

<xs:complexType name="abcType">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:choice>
            <xs:element name="a"/>
            <xs:element name="b"/>
        </xs:choice>
        <xs:element name="c"/>
    </xs:choice>
</xs:complexType>

由于选择操作的性质,这反过来又等价于:

<xs:complexType name="abcType">
    <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="a"/>
        <xs:element name="b"/>
        <xs:element name="c"/>
    </xs:choice>
</xs:complexType>

...这就是你想要的。

如果您也有属性,那么您可能还需要定义一个可以扩展的公共基类。使用此方案,只有没有派生类的类才应具有元素,因为基元素上元素的存在会强制排序。

我们在这里有效地做的是将选择元素的继承与元素层次结构本身分开定义。

1赞 Manfred Stadel 12/14/2016 #4

如果你的重点是扩展而不是类型继承,那么可以通过重新定义 a 来扩展 a,如下所示:<choice><group>

包含基本架构的文件“abc.xsd”:

<schema 
    xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="any" 
    xmlns:n="any" 
    elementFormDefault="qualified">

    <group name="baseGroup">
        <choice>
            <element name="a"/>
            <element name="b"/>
            <element name="c"/>
        </choice>
    </group>

    <complexType name="choiceType">
        <sequence minOccurs="0" maxOccurs="unbounded">
            <group ref="n:baseGroup"/>
        </sequence>
    </complexType>

    <element name="test">
        <complexType>
            <sequence>
                <element name="sample" type="n:choiceType" maxOccurs="unbounded"/>
            </sequence>
        </complexType>
    </element>
</schema>

文件“abcdef.xsd”扩展了基本架构中的定义:<choice>

<?xml version="1.0"?>
<schema 
    xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="any"
    xmlns:n="any" 
    elementFormDefault="qualified">

    <redefine schemaLocation="abc.xsd">
        <group name="baseGroup">
            <choice>
                <group ref="n:baseGroup"/>
                    <element name="d"/>
                    <element name="e"/>
        </choice>
            </group>
    </redefine>
</schema>

这将验证以下 xml 文件,例如:

<?xml version="1.0" encoding="UTF-8"?>
<test 
    xmlns="any"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="any ../schemas/abcde.xsd">

    <sample>
        <a/>
        <c/>
        <b/>
        <a/>
    </sample>

    <sample>
        <c/>
</sample>

    <sample>
    </sample>

    <sample>
        <a/>
        <e/>
        <b/>
        <d/>
        <a/>
    </sample>
</test>
0赞 Mohammed Suhail 4/24/2020 #5

它非常简单,您可以使用“choice”关键字并设置其出现次数

<xs:element name="Product">
 <xs:complexType>
  <xs:sequence>
   <xs:choice minOccurs="1" maxOccurs="14">
   <xs:element>
   </xs:element>
   // Post your element configuration here
   </xs:choice>
  </xs:sequence>
 </xs:complexType>