Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
413 views
in Technique[技术] by (71.8m points)

xsd - How to extend a choice complexType without sequencing the choice?

I have a choice complexType named abType:

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

This type can be used to create elements with a and b nodes in any order like this for example:

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

Now I want to create a derived type called abcType to allow the nodes a, b and c in any order. Therefore I created a new complexType based on abType:

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

After that I created a abc node:

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

But this node is invalid! It is not valid to put any a or b after a c. The reason is, that deriving a type from a base type creates an implicite sequence although both types are choices. XMLspy illustrates it in this way:

Extended Choice Type

This result is quite useless for choice types.

So my question is: How to extend a choice type without sequencing the choice?

Here is the complete XSD and an XML test file to reproduce the problem:

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

Example:

<?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>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is a way to do this that relies on the fact that a choice within a choice acts as a bigger choice.

First, define an element group which contains a single choice from all the elements within the base element:

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

Then you can use this in your definition of abElement in place of the elements you had before:

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

If you need an extended type, then you can extend the choice:

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

This is equivalent to:

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

And because of the nature of the choice operation, this is in turn equivalent to:

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

...which is what you want.

If you have attributes as well, then you may also need to define a common base class which you can extend. With this scheme, only classes with no derived classes should have elements, as it's the presence of elements on the base elements that forces the sequencing.

What we are effectively doing here is defining the inheritance of choice elements separately from the elements hierarchy itself.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...