Re: Extensibility Question

Hi Michael,

>I'm a relative newbie to XSDL (but an experienced markup developer),
>so kindly excuse my ignorance if it should rear it's ugly head. I'm
>developing a system interface schema and we'd like to leverage XSDL's
>potential for datatype validation. For "internal" processes we have a
>generic structure containing parameters, where each parameter has
>attributes for name, type and direction (essentially name/value pairs).
>Like so:
>
><parameter name="input1" datatype="Int" direction="In">
>     <value>1</value>
></parameter>
><parameter name="output1" datatype="Int" direction="Out">
>     <value>2</value>
></parameter>
>
> This is fine for our puposes, but when we add external interfaces into the
>mix we'll need to support more complex data exchange requirements. Most
>likely, each interface will use its own schema, which can't be shoe-horned
>in to our parameter structure (mostly because they'll want to validate
>their datatypes at the parser level). While this is unavoidable, I'd prefer
>that every interface used the rest of our mesasge framework so that we can
>standardize on ways to handle things like authentication information. So
>I'm considering doing something in my schema like (pseudo-spec):
>
><choice>
>   <!element name="parameters"/>
>   <any namespace=""##other"/>
></choice>
>
>Any thoughts on whether this would be good, bad, done better some other way
>would be most appreciated. TIA.
>
I guess this depends on how much control you want to have over the 
external interfaces that can be added. If you use <xs:any> you don't 
really have any control at all and the external interfaces can pretty 
much add whatever they want.
For more control I think this is a good use-case for substitutionGroups 
which allows one element to serve as a model in your schema and then the 
external interfaces could define their own "parameter" elements that can 
be used instead of the model. The base schema would contain the 
complexType that serves as the base type for the parameter-model element 
as well as the structure of your main schema. To illustrate I will use 
the following example:

Base schema:
--------------
<?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>
        <!-- This is the content model that defines the parameter 
elements. Instead of having a choice between "parameter" and "any" this 
is now zero-or-more parameterModel elements. -->
      <xs:sequence>
        <xs:element ref="parameterModel" minOccurs="0" 
maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
   
  <!-- The "parameterModel" element is declared as abstract which means 
that it cannot by itself appear in an instance document. Instead one of 
the elements that are defined in the substitutionGroup for 
"parameterModel" must appear in the instance document. -->
  <xs:element name="parameterModel" type="parameterBase" abstract="true"/>

  <!-- Define the base type for the elements that can substitute the 
parameterModel element so that they at least must contain a "name" 
attribute. -->
  <xs:complexType name="parameterBase">
    <xs:attribute name="name" use="required" type="xs:string"/>
  </xs:complexType>
   
  <!-- Define the type for the local parameter element. This type must 
be derived from the "parameterBase" type so that any element of this 
type can be used instead of the "parameterModel" element. -->
  <xs:complexType name="myParameterType">
    <xs:complexContent>
      <xs:extension base="parameterBase">
        <xs:sequence>
          <xs:element name="value" type="xs:string"/>
        </xs:sequence>
        <xs:attribute name="datatype" type="xs:string" use="required"/>
        <xs:attribute name="direction" type="xs:string" use="required"/>
    </xs:extension>
    </xs:complexContent>
  </xs:complexType>
 
  <!-- Finally we define the local parameter element that can appear 
instead of the "parameterModel" in the instance document. This element 
is defined to be in the substitutionGroup of the "parameterModel" 
element.-->
  <xs:element name="myParameter" type="myParameterType" 
substitutionGroup="parameterModel"/>   
</xs:schema>

Now, if only the above schema was used then an instance document could 
look like this (Note that the "myParameter" element is used instead of 
the "parameterModel" element.):

<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <myParameter name="input1" datatype="Int" direction="In">
    <value>1</value>
  </myParameter>
  <myParameter name="output1" datatype="Int" direction="Out">
    <value>2</value>
  </myParameter>
</Root>

Now to extend this with an external interface that will define its own 
parameter element this can be done in a separate schema that will 
include the base schema. Here is an example:

External schema:
-----------------
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
elementFormDefault="qualified" attributeFormDefault="unqualified">
  <!-- Include the base schema -->
  <xs:include schemaLocation="substGroup_base.xsd"/>

  <!-- This is the type definition for the external parameter elements. 
This type must also derive from the "parameterBase" type so that the 
elements with this type can be used instead of the "parameterModel" 
element.-->
  <xs:complexType name="externalParameterType">
    <xs:complexContent>
      <xs:extension base="parameterBase">
        <xs:sequence>
          <xs:element name="value" type="xs:string"/>
          <xs:element name="external" type="xs:string"/>
        </xs:sequence>
        <xs:attribute name="externalAtt" type="xs:string" use="required"/>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType> 
 
  <!-- The external parameter elements are declared in the 
substitutionGroup of the "parameterModel" element and can hence be used 
instead of this element in the instance document.-->
  <xs:element name="externalParameter" type="externalParameterType" 
substitutionGroup="parameterModel"/>
</xs:schema>

In this external schema we have defined a new type that defines the 
external parameter elements (here called "externalParameter"). Since 
these elements can be used instead of the "parameterModel" elements in 
the instance document an instance that conforms to this schema can look 
like this:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <myParameter name="input1" datatype="Int" direction="In">
    <value>1</value>
  </myParameter>
  <myParameter name="output1" datatype="Int" direction="Out">
    <value>2</value>
  </myParameter>
  <externalParameter name="ext1" externalAtt="whatever">
    <value>3</value>
    <external>55</external>
  </externalParameter>
</Root>

This is made possible becuase the externalParameter element is declared 
to be in the substitutionGroup of the parameterModel element.

I'm not sure if this match your design criteria but it seems it would 
fit in well with your description above. The drawback with this method 
is that all the elements involved in the substitutionGroup must be 
declared as global elements.
For more information on substitutionGroups see [1].

Hope this was of some help,
Cheers,
/Eddie

[1] http://www.w3.org/TR/xmlschema-0/#SubsGroups

Received on Tuesday, 6 August 2002 21:39:43 UTC