W3C home > Mailing lists > Public > xmlschema-dev@w3.org > September 2002

Re: an Schema for this xml?

From: Eddie Robertsson <erobertsson@allette.com.au>
Date: Tue, 03 Sep 2002 10:05:56 +1000
Message-ID: <3D73FCE4.5030208@allette.com.au>
To: Jeni Tennison <jeni@jenitennison.com>
CC: xmlschema-dev@w3.org, Marcos Mayorga <marcos.mayorga@grupotecnobit.com>

Hi Marcos,

>>how can write an schema where an element has two ways of be
>>described?
>>    
>>
>
>You can't, I'm afraid, not using W3C XML Schema, at least not if the
>element appears with the two different types in the same content
>model. W3C XML Schema has a constraint that says that in a particular
>content model, all the element particles with a particular name must
>have the same type as well. It also doesn't have the facility of
>allowing element content to be determined by what attributes are there
>or not (co-occurrence constraints).
>
Jeni is absolutely correct that you can't do exactly what you want in 
W3C XML Schema and the only way to get this is to embedd some Schematron 
rules as Jeni described. However, there is another option that will get 
to close to what you're asking for even if it won't go all the way. This 
option does require that you have control of the instance document so 
that you can specify the type you want to use by inserting an xsi:type 
attribute [1].
Here is an example schema:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
elementFormDefault="qualified" attributeFormDefault="unqualified">
  <xs:complexType name="CTBase"/>

  <xs:complexType name="CT1">
    <xs:complexContent>
      <xs:extension base="CTBase">
        <xs:sequence>
          <xs:element name="brain" type="xs:string"/>
        </xs:sequence>
        <xs:attribute name="att1" type="xs:string"/>
        <xs:attribute name="att2" type="xs:string"/>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
 
  <xs:complexType name="CT2">
    <xs:complexContent>
      <xs:extension base="CTBase">
        <xs:attribute name="href" type="xs:anyURI"/>
        <xs:attribute name="path" type="xs:string"/>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
 
  <xs:element name="something" type="CTBase"/>
</xs:schema>

As you can see this schema is very similar to the example you provided 
with one exception. The use of xsi:type requires that the types you want 
to choose from are derived from the same base type. This is why I have 
created an empty base type "CTBase" that CT1 and CT2 both extends to 
create the desired content.
When you create your instance document you need to also specify the 
xsi:type attribute to identify which of the derived types to use for 
validation.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<something xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xsi-type.xsd" xsi:type="CT2" 
href="www.test.com"/>

or

<?xml version="1.0" encoding="UTF-8"?>
<something xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xsi-type.xsd" xsi:type="CT1" att1="aaa">
  <brain></brain>
</something>

NOTE that if you forget to specify the xsi:type attribute in the 
instance document then an empty element will also validate:

<?xml version="1.0" encoding="UTF-8"?>
<something xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xsi-type.xsd"/>

If you have full control over the generation of the instance document 
then this approach could work for you. If you don't then I think the 
embedded Schematron rules are the best bet (unless you want to switch to 
RELAX-NG).

Cheers,
/Eddie

>
>You can specify a general type for the element that covers both your
>possibilities:
>
>  <xs:element name="myelement">
>    <xs:complexType mixed="true">
>      <xs:sequence>
>        <xs:element ref="mynestedelement" minOccurs="0" />
>      </xs:sequence>
>      <xs:attribute name="name" type="xs:NMTOKEN" />
>      <xs:attribute name="a" type="xs:integer" />
>      <xs:attribute name="b" type="xs:integer" />
>      <xs:attribute name="href" type="xs:anyURI" />
>      <xs:attribute name="path" type="xs:token" />
>    </xs:complexType>
>  </xs:element>
>
>and then have a separate Schematron rule that tests the combinations,
>for example:
>
>  <sch:rule context="myelement">
>    <sch:assert test="(@name and @a and @b and mynestedelement and
>                       not(@href) and not(@path)) or
>                      (@href and @path and
>                       not(@name) and not(@a) and not(@b) and not(*))">
>      "myelement" elements must either have a name, a and b attributes
>      and a mynestedelement child or have an href and a path
>      attribute.
>    </sch:assert>
>  </sch:rule>
>
>Or you can switch to a different schema language, such as RELAX NG,
>which does support this kind of thing:
>
>  <element name="myelement">
>    <choice>
>      <group>
>        <attribute name="name"><data type="xs:NMTOKEN" /></attribute>
>        <attribute name="a"><data type="xs:integer" /></attribute>
>        <attribute name="b"><data type="xs:integer" /></attribute>
>        <ref name="mynestedelement" />
>      </group>
>      <group>
>        <attribute name="href"><data type="xs:anyURI" /></attribute>
>        <attribute name="path"><data type="xs:token" /></attribute>
>        <text />
>      </group>
>    </choice>
>  </element>
>
>Cheers,
>
>Jeni
>
>---
>Jeni Tennison
>http://www.jenitennison.com/
>
>  
>
Received on Monday, 2 September 2002 20:06:52 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Tuesday, 11 January 2011 00:14:34 GMT