15

Is it possible to define in XML Schema an condition based on attribute value? For example, when test@attrib="one", I want one-element to be allowed and mandatory or when test@attrib="two", I want two-element to be allowed and mandatory.

For example, valid documents are:

<root>
    <test attrib="one"/>
    <some-element-1/>
    <some-element-2/>
    ...
    <some-element-n/>
    <one-element>
    </one-element>
</root>

or

<root>
    <test attrib="two"/>
    <some-element-1/>
    <some-element-2/>
    ...
    <some-element-n/>
    <two-element>
    </two-element>
</root>

Wrong documents:

<root>
    <test attrib="one"/>
    <some-element-1/>
    <some-element-2/>
    ...
    <some-element-n/>
</root>

or

<root>
    <test attrib="two"/>
    <some-element-1/>
    <some-element-2/>
    ...
    <some-element-n/>
    <one-element>
    </one-element>
</root>

Is it possible in XSD?

Pol
  • 5,064
  • 4
  • 32
  • 51

1 Answers1

12

Not within the same type. You would need to define a different type for each of the different options.

UPDATE

To re-use type definitions in your schema:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" 
           xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns="http://My.Schema.Namespace" 
           targetNamespace="http://My.Schema.Namespace">

  <xs:element name="root">
    <xs:complexType>
      <xs:choice>
        <xs:element name="test1" type="test1Type" />
        <xs:element name="test2" type="test2Type" />
      </xs:choice>
    </xs:complexType>
  </xs:element>

  <!-- define the two root types -->
  <xs:complexType name="test1Type">
    <xs:all>
      <xs:element name="some-element-1" type="some-element-1Type" />
      <xs:element name="some-element-2" type="some-element-2Type" />
      <xs:element name="some-element-3" type="some-element-3Type" />
      <xs:element name="one-element" type="one-elementType" />
    </xs:all>
    <xs:attribute name="attrib" type="xs:string" fixed="one" />
  </xs:complexType>

  <xs:complexType name="test2Type">
    <xs:all>
      <xs:element name="some-element-1" type="some-element-1Type" />
      <xs:element name="some-element-2" type="some-element-2Type" />
      <xs:element name="some-element-3" type="some-element-3Type" />
      <xs:element name="two-element" type="two-elementType" />
    </xs:all>
    <xs:attribute name="attrib" type="xs:string" fixed="two" />
  </xs:complexType>

  <!-- Define re-usable types-->
  <xs:complexType mixed="true" name="some-element-1Type"/>
  <xs:complexType mixed="true" name="some-element-2Type"/>
  <xs:complexType mixed="true" name="some-element-3Type"/>
  <xs:complexType mixed="true" name="one-elementType"/>
  <xs:complexType mixed="true" name="two-elementType"/>

</xs:schema>

This will validate:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="http://My.Schema.Namespace">
  <test1 attrib="one">
    <some-element-1>sadas</some-element-1>
    <some-element-2>sadas</some-element-2>
    <some-element-3>sadas</some-element-3>
    <one-element>sadas</one-element>
  </test1>
</root>

and

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="http://My.Schema.Namespace">
  <test2 attrib="two">
    <some-element-1>sadas</some-element-1>
    <some-element-2>sadas</some-element-2>
    <some-element-3>sadas</some-element-3>
    <two-element>sadas</two-element>
  </test2>
</root>
tom redfern
  • 30,562
  • 14
  • 91
  • 126
  • So I need to define also `` two times for each case? – Pol Jan 10 '12 at 10:06
  • No you can define a known type at the schema root level and re-use it. Please see my update. – tom redfern Jan 10 '12 at 10:20
  • Thanks. For defining two types should I use `xs:attribute` (with `fixed` attribute) and `xs:choice`? – Pol Jan 10 '12 at 10:29
  • You can use either the fixed or the default value for the attribute. Use fixed if you don't want this to be changed. The choice indicator should be used to express "select one of the following". So if you want to restrict an instance to implement one of the two "test" elements then yes, you would use a choice. – tom redfern Jan 10 '12 at 10:37
  • When I specify default value for attribute doesn't it mean that other value is still valid? Default may be 'one' but 'two' will be still valid for case dedicated to 'one' only. – Pol Jan 10 '12 at 11:33
  • Yes if you specify default then other values are allowed. – tom redfern Jan 10 '12 at 11:36
  • Can you provide complete example XSD? – Pol Jan 10 '12 at 11:53
  • 1
    See my update. The only problem is you cannot use the same name for both test nodes. XSD does not allow two nodes with different types to share the same name within the same scope. – tom redfern Jan 10 '12 at 13:27
  • 1
    Thank you very much!. So `test1` and `test2` can't be named just `test`? In this case condition is in fact by element name not by attribute value, if I understood you correctly. If so, I understand that condition by attribute value is unpossible in XSD. – Pol Jan 10 '12 at 14:12
  • 6
    Yes it's impossible to do what you originally wanted – tom redfern Jan 10 '12 at 14:30
  • Ok, I am making this an answer. – Pol Jan 10 '12 at 15:38