[xsd-users] Schema and inheritance

Vera Mickael vera.mickael at free.fr
Mon Sep 12 11:31:20 EDT 2005


Boris Kolpackov a écrit :
> Mickael,
> 
> Vera Mickael <vera.mickael at free.fr> writes:
> 
> 
>>Tell me if I'm wrong but I think inheritance is not really
>>supported by schema. Suppose I define an element type A and
>>another one B that extends A and another one C that extends
>>A. In my schema if I define another element type X that
>>contains A, I can't use B or C in an XML file instead of A
>>in an element of type X.
> 
> 
> There are two ways to do this in XML Schema: xsi:type or
> substitution groups.
> 
> xsi:type is the simplest of the two but it requires you to explicitly
> specify the type of the element in the instance document. Suppose
> we have the following schema:
> 
> <xsd:complexType name="Person">
>   <xsd:sequence>
>     <xsd:element name="name" type="xsd:string"/>
>   </xsd:sequence>
> </xsd:complexType>
> 
> <xsd:complexType name="Superman">
>   <xsd:complexContent>
>     <xsd:extension base="Person">
>       <xsd:attribute name="can_fly" type="xsd:boolean"/>
>     </xsd:extension>
>   </xsd:complexContent>
> </xsd:complexType>
> 
> <xsd:element name="person" type="Person"/>
> 
> In the instance document we can have something like this:
> 
> <person>
>   <name>Boris Kolpackov</name>
> </person>
> 
> <person xsi:type="Superman" can_fly="true">
>   <name>Boris Kolpackov</name>
> </person>
> 
> 
> Substitution groups are much more elaborate (on the schema level).
> In this case you use different element names to convey the type
> information. Here is an example schema (assuming definitions of
> Person and Superman from above):
> 
> <xsd:element name="person" type="Person"/>
> <xsd:element name="superman" type="Superman" substitutionGroup="person"/>
> 
> <xsd:complexType name="BusinessCard">
>   <xsd:sequence>
>     <xsd:element ref="person"/>
>   </xsd:sequence
> </xsd:complexType>
> 
> <xsd:element name="business-card" type="BusinessCard"/>
> 
> In the instance document we can have something like this:
> 
> <business-card>
>   <person>
>     <name>Boris Kolpackov</name>
>   </person>
> </business-card>
> 
> <business-card>
>   <superman can_fly="true">
>     <name>Boris Kolpackov</name>
>   </superman>
> </business-card>
> 
> 
>>So we use another element type that is a choice between B
>>and C, and wherever we want B or C in the schema we use the
>>choice. The generated code is very ugly, we obtain something
>>close to a union in C langage.
>>
> 
> 
> For the following schema
> 
> <xsd:complexType name="PersonOrSuperman">
>   <xsd:choice>
>     <xsd:element name="person" type="Person"/>
>     <xsd:element name="superman" type="Superman"/>
>   </xsd:sequence
> </xsd:complexType>
> 
> the code that uses xsd-generated mapping would look like this:
> 
> PersonOrSuperman ps = ...
> 
> if (ps.person.present ())
> {
>   Person p = ps.person ();
> }
> else
> {
>   Superman s = ps.superman ();
> }
> 
> Not very pretty, I agree.
> 
> 
> 
>>How does xsd handle this problem ? I want to describe a
>>model with two or more classes that extend a class, what is
>>important to me is the quality of the generated code,
>>polymorphism in this case.
>>
> 
> 
> Those are actually very interesting questions. As you can see
> from above, XML Schema does have provisions for instance (data)
> polymorphism. The question that you probably would like to ask
> is how we can take advantage of this in a language mapping
> (binding). The problem is that the data polymorphism is quite
> useless without the behavior polymorphism which can take advantage
> of this extra data.
> 
> Here is what I mean. Suppose, for the schema above, we have
> the following mapping:
> 
> struct Person
> {
>   string
>   name () const;
> };
> 
> struct Superman: Person
> {
>   bool
>   can_fly () const;
> };
> 
> struct BusinessCard
> {
>   Person&
>   person ();
> };
> 
> Here BusinessCard::person can return a reference to either a Person
> or a Superman. The question is how is this useful to us? Since
> there is no behavior associated with Person or Superman (they are
> both "pure data" types), there is no real use to this feature.
> There is no way to get hold of the can_fly() other than explicit
> casting which is not any better than the choice approach you
> described above. I am still thinking about this but at the moment
> I can't see how XML Schema provisions for polymorphism can be
> useful in the language mapping.
> 
> hth,
> -boris
> 

Thank you very much for your explanations about XSD and 
inheritance.

About polymorphism, BusinessCard::person returning a person 
may be intersting if the code manipulates a person for its 
common attributes. I agree the interest may be limited.

I've been thinking about those problems for a long time. I 
did not found any satisfying solution. I guess you thought 
about a factory provided by the user.

One solution would be to provide a factory at parsing time, 
each time the parser needs to instantiate an obect it asks 
the factory to do it. The user may have its own classes 
instanciated or the factory instanciates the default 
generated classes. User classes inherit from generated 
classes. The major problem is that generated classes use 
relations to generated classes, the user stil have to cast 
to its own classes.

The second solution is to provide a factory at generation 
time. This way the parser generator can generate relations 
to user classes. The problem is that you have circular 
dependencies between the classes generated and the user 
classes. I use components and I can't have circular 
dependencies between components.

I didn't think more about it as I worked with Java and these 
solutions use multiple inheritance. I think the second 
solution can be implemented in C++.

Mickaël





More information about the xsd-users mailing list