Josh Winkler
Josh Winkler

Reputation: 165

xsd choice override

I need to define a set of XSDs. Each XSD will have a header element, and that header is identical, except for some elements in the middle.

So, I would have:

xml1:

<req1>
    <head>
        <common1/>
        <common2/>
        <choice1/>
        <choice2/>
        <common3/>
    </head>
    <data1>...</data1>
</req1>

xml2:

<req2>
    <head>
        <common1/>
        <common2/>
        <choice2/>
        <choice3/>
        <common3/>
    </head>
    <data2>...</data2>
</req2>

where choice1, choice2, choice3 is in a <choice> set, like

<choice>
    <choice2/>
    <choice3/>
</choice>

and can have different choices and numbers of elements between the different request types.

I would really like to be able to define this in a single XSD for the header, and then include that in req1.xsd and req2.xsd. I can't figure out how to swap this <choice> out dynamically. If I didn't have the <common3/> part, I could use a base element, but my understanding is that when I add anything to a base, it only adds at the end. Any way I can replace in the middle, or add in the middle when using a base?

Upvotes: 2

Views: 1574

Answers (1)

Petru Gardea
Petru Gardea

Reputation: 21658

One way to do it is by using substitution groups. You define a base XSD, for your boilerplate.

Base.xsd

<?xml version="1.0" encoding="utf-8"?>
<!--W3C Schema generated by QTAssistant/XML Schema Refactoring Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="head">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="common1" type="xsd:anyType"/>
                <xsd:element name="common2" type="xsd:anyType"/>
                <xsd:element ref="headerPlaceholder"/>
                <xsd:element name="common3" type="xsd:anyType"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="headerPlaceholder" type="headerPlaceholder" abstract="true"/>
    <xsd:complexType name="headerPlaceholder" abstract="true"/>
    <xsd:complexType name="request" abstract="true">
        <xsd:sequence>
            <xsd:element ref="head"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:schema>

Then you can build your req1 and req independently.

Req1.xsd

<?xml version="1.0" encoding="utf-8"?>
<!--W3C Schema generated by QTAssistant/XML Schema Refactoring Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:include schemaLocation="SubstitutionGroupHeader.xsd"/>

    <xsd:element name="req1" type="req1"/>
    <xsd:complexType name="req1">
        <xsd:complexContent>
            <xsd:extension base="request">
                <xsd:sequence>
                    <xsd:element name="data1"/>
                </xsd:sequence>         
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:element name="choice1" substitutionGroup="headerPlaceholder">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="headerPlaceholder"/>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="choice2" substitutionGroup="headerPlaceholder">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="headerPlaceholder"/>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>  
</xsd:schema>

The structure looks like this:

Req 1

Req2.xsd

<?xml version="1.0" encoding="utf-8"?>
<!--W3C Schema generated by QTAssistant/XML Schema Refactoring Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:include schemaLocation="SubstitutionGroupHeader.xsd"/>

    <xsd:element name="req2" type="req2"/>
    <xsd:complexType name="req2">
        <xsd:complexContent>
            <xsd:extension base="request">
                <xsd:sequence>
                    <xsd:element name="data2"/>
                </xsd:sequence>         
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:element name="choice3" substitutionGroup="headerPlaceholder">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="headerPlaceholder"/>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="choice4" substitutionGroup="headerPlaceholder">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="headerPlaceholder"/>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>  
</xsd:schema>

The structure for req2:

req 2

I put choice1/2 and choice3/4 in req1 and req2 just to have no overlap between content. So the file structure looks something like this:

XSD File relationships

The overall relationship between XSD components:

QTAssistant XSD component relationships diagram

If you want to have the same choice2 referenced from both req1 and req2, you would have to refactor choice2 in its own file, etc.

A lot could be discussed about choices vs substitution groups, but that's another thing...

Upvotes: 3

Related Questions