1

I have complex type, History, which should extend my complex type, Section, while prohibiting one inherited attribute (Title). How can I achieve this?

Example

<xs:complexType name="Section">
    <xs:sequence minOccurs="1" maxOccurs="1">
        <xs:choice minOccurs="1" maxOccurs="unbounded">
            <!-- ... -->
        </xs:choice>

        <xs:element name="Section" type="Section" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>

    <xs:attribute name="Key" type="xs:string"/>
    <xs:attribute name="Title" type="xs:string"/>
</xs:complexType>

<xs:complexType name="History">
    <xs:complexContent>
        <xs:extension base="Section">
            <!-- Prohibit/remove "Title" attribute from parent. -->
            <xs:attribute name="Title" use="prohibited"/>

            <!-- Add more attributes. -->
            <xs:attribute name="StartDate" type="xs:date" use="required"/>
            <xs:attribute name="EndDate" type="xs:date"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

What's the proper way to do this?

Josh M.
  • 26,437
  • 24
  • 119
  • 200

1 Answers1

1

EDITED: answer completly writed from scratch as the first one was not correct (see comments).

I know two ways of doing that:

Option 1: use both xs:restriction (in order to prohibit attribute) and xs:extension (in order to add more content)

<xs:group name="baseGroup">
    <xs:sequence>
        <xs:choice minOccurs="1" maxOccurs="unbounded">
            <!-- ... -->
        </xs:choice>

        <xs:element name="Section" type="Section" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:group>

<xs:complexType name="Section">
    <xs:group ref="baseGroup"></xs:group>
    <xs:attribute name="Key" type="xs:string"/>
    <xs:attribute name="Title" type="xs:string"/>
</xs:complexType>

<xs:complexType name="HistoryWithoutTitle">
    <xs:complexContent>
        <xs:restriction base="Section">
            <!-- Inherit the group (only attributes are inherited) -->
            <xs:group ref="baseGroup"></xs:group>
            <!-- Prohibit/remove "Title" attribute from parent. -->
            <xs:attribute name="Title" type="xs:string" use="prohibited"/>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType>    

<xs:complexType name="History">
    <xs:complexContent>
        <xs:extension base="HistoryWithoutTitle">
            <!-- Add more attributes. -->
            <xs:attribute name="StartDate" type="xs:date" use="required"/>
            <xs:attribute name="EndDate" type="xs:date"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

Option 2: using a "interface" with the common content and attributes, and then make two types (Section and History) which extends from that interface adding the new content. This is the option I prefer, because you can easily add new attributes to both elements or only to one.

<!-- This is what both Section and History have in common (similar to an interface) -->
<xs:complexType name="common">
    <!-- Content in both Section and History -->
    <xs:sequence>
        <xs:choice minOccurs="1" maxOccurs="unbounded">
            <!-- ... -->
        </xs:choice>

        <xs:element name="Section" type="Section" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    <!-- Attributes in both Section and History -->
    <xs:attribute name="Key" type="xs:string"/>        
</xs:complexType>

<xs:complexType name="Section">
    <xs:complexContent>
        <xs:extension base="common">
            <!-- New attributes -->
            <xs:attribute name="Title" type="xs:string"/>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

<xs:complexType name="History">
    <xs:complexContent>
        <xs:extension base="common">
            <!-- New attributes -->                
            <xs:attribute name="StartDate" type="xs:date" use="required"/>
            <xs:attribute name="EndDate" type="xs:date"/>
        </xs:extension>
    </xs:complexContent>        
</xs:complexType>
sergioFC
  • 5,926
  • 3
  • 40
  • 54
  • Ah, yeah that makes sense. Unfortunate you have to create a new type to do this though, instead of being able to use both `xs:restriction` and `xs:extension` on the same type. Thanks! – Josh M. Jan 30 '15 at 13:14
  • While this solution makes sense, I tried it and now the `History` type no longer accepts child elements: "The element History cannot contain child element X because the parent element's content model is empty." Although the parent's content model is *not* empty - it's as if the restriction clobbered the content model, too? – Josh M. Jan 30 '15 at 15:19
  • I was wrong. It seems that when restricting an element only attributes are inherited. If you want to inherit also the group (sequence) you have to include it also in the restricted type. Source is in [this question](http://stackoverflow.com/a/14801341/3870761) . I updated my question definig two new ways, I prefer the second one, maybe another user knows a better answer, as I think this is getting over-complicated. – sergioFC Jan 30 '15 at 18:38