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

时间:2012-01-25 19:04:46

标签: xsd

我可以选择名为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>

现在我想创建一个名为abcType的派生类型,以便以任何顺序允许节点abc。因此,我基于abType创建了一个新的complexType:

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

但此节点无效!在a之后放置任何bc无效。原因是,从基类型派生类型会创建一个隐含序列,尽管两种类型都是选择。 XMLspy以这种方式说明了它:

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>

5 个答案:

答案 0 :(得分:14)

有一种方法可以做到这一点,这取决于选择中的选择是一个更大的选择。

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

<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 :(得分:11)

不幸的是,简短的回答是NO,你无法扩展选择合成器。从逻辑上讲,如果a,b和c之间存在某种关系(如Java,.NET,一切最终都是对象,你可以在XSD中做同样的事情)那么我建议改用替换组(或者,如果你愿意,可以选择基于xsi:type的东西。

更新一个例子。 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

可扩展性是指在某个时间点,您可能只有 a b c 作为成员。如果您或消费者决定添加某些内容(例如 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

答案 2 :(得分:1)

替换的另一个例子。

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

abcExtension.xml

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

abcdExtension.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>

答案 3 :(得分:0)

如果您的重点是扩展而非类型继承,则可以通过重新定义<choice>来扩展<group>,如下所示:

文件&#34; abc.xsd&#34;包含基本模式:

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

文件&#34; abcdef.xsd&#34;扩展基础架构中定义的<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>

答案 4 :(得分:0)

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

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