问题
I am kinda repeating this question bit the 1st time it was asked incorrectly.
I have this:
<xsd:complexType name="A">
<xsd:sequence>
<xsd:element name="options" type="options"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="B">
<xsd:complexContent>
<xsd:element name="options" type="ex_options"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="options">
<xsd:sequence>
...some options
</xsd:sequence>
</xsd:element>
<xsd:complexType name="ex_options">
<xsd:complexContent>
<xsd:extension base="options">
<xsd:sequence>
...some more options
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:element>
So basically I have class A with an inner class of options Class B inherits from class A and I want B.options to inherit from A.options so that when we do webservices we only need to pass a and when we call getOptions it will return the right object B.options. Currently with the way the xsd stands I get an error saying multiple elements with name options with different types appear in the model group. The errors is in the B type.
回答1:
Just stick with elements of type B and then use then decorate your instance document elements as described below with the appropriate xsi:type
attribute value.
<xsd:complexType name="B">
<xsd:complexContent>
<xsd:element name="options" type="ex_options"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="options">
<xsd:sequence>
...some options
</xsd:sequence>
</xsd:element>
<xsd:complexType name="ex_options">
<xsd:complexContent>
<xsd:extension base="options">
<xsd:sequence>
...some more options
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:element>
and then "decorate" your instance element as either
<options xsi:type="ex_options"> ... (this will work)
or
<options xsi:type="options"> ... (I think you can do this as long as the base xsi:type is not abstract)
If it turns out that you can't decorate with the base xsi:type
,
then you can always "cheat" by creating an empty base type and then
extending by careful construction to arrive at your two desired formats.
See this post for more elaboration & links.
回答2:
You could make the options
sequence open-ended so you can have any number of options and then validate the existing options based on an attribute value. For example, in the following schema, the options
list has a type
attribute of either A
or B
, indicating which options should actually get listed:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xs"
elementFormDefault="qualified"
xmlns="http://tempuri.org/XMLSchema.xs"
xmlns:mstns="http://tempuri.org/XMLSchema.xs"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Elements for document structure. -->
<!-- This section is just for validating my example file to -->
<!-- demonstrate the schema. -->
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="elementA" type="A" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="elementB" type="A" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- The important part of the schema. -->
<!-- Types -->
<!-- A has options of type options. -->
<xs:complexType name="A">
<xs:sequence>
<xs:element name="options" type="options"/>
</xs:sequence>
</xs:complexType>
<!-- Options specifies a options with a type attribute specifying which options will be available. -->
<xs:complexType name="options">
<xs:sequence>
<xs:element name="option" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="type" use="optional" default="A">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="A"/>
<xs:enumeration value="B"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>
Here is an example of the XML for this schema.
<?xml version="1.0" encoding="utf-8"?>
<root xmlns="http://tempuri.org/XMLSchema.xs">
<elementA>
<options type="A">
<option>Test-A</option>
<option>Test2-A</option>
</options>
</elementA>
<elementB>
<options type="B">
<option>Test-B</option>
<option>Test2-B</option>
<option>Test3-B</option>
<option>Test4-B</option>
</options>
</elementB>
</root>
回答3:
You may also use restriction rather than extension, but it is not best solution, because restriction removes all base definitions. Better case is use xsi:type at runtime (in XML instances of elements) like described in other answer.
More one example of using xsi:type is here: http://www.xfront.com/ElementHierarchy.html
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- Root element -->
<xsd:element name="root" type="B"/>
<!-- Base abstract type -->
<xsd:complexType name="A" abstract="true">
<xsd:sequence>
<!-- Option that we will override -->
<xsd:element name="options" type="options"/>
</xsd:sequence>
</xsd:complexType>
<!-- Derived type -->
<xsd:complexType name="B">
<xsd:complexContent>
<!--Overriding -->
<xsd:restriction base="A">
<xsd:sequence>
<xsd:element name="options" type="ex_options"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<!-- Base included class -->
<xsd:complexType name="options">
<xsd:sequence>
<xsd:element name="baseOption"/>
</xsd:sequence>
</xsd:complexType>
<!-- Overriding of included class -->
<xsd:complexType name="ex_options">
<xsd:complexContent>
<xsd:restriction base="options">
<xsd:sequence>
<xsd:element name="overridedOption"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
In pseudo CiXML it will something like:
{
B root;
abstract class A
{
options options;
}
class B override A
{
ex_options options;
}
class options
{
empty baseOption;
}
class ex_option override options
{
empty overridedOption
}
}
Here the example XML:
<?xml version="1.0" encoding="UTF-8"?>
<root xsi:noNamespaceSchemaLocation="polymorphism.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<options>
<overridedOption/>
</options>
</root>
来源:https://stackoverflow.com/questions/208612/xsd-and-polymorphism