Search code examples
xmlif-statementxsdconditional-statementsassert

XSD 1.1: Use of attribute only when another not required attribute is present


I am supposed to write a xsd for a simple and small restaurant simulator. For this simulator I have a number of elements that are all considered to be food. Some of them need no further attributes since they are ready to go. However some of these food-elements need preparation and some of the elements that need preparation also should only be allowed to be prepared if something else is present. For this, they should be given the attribute "condition" (see example):

<food>
   <name>tea</name>
   <preparation>Ready to Go</preparation>
</food>

<food>
   <name>sandwich</name>
   <preparation time="2">Toaster</preparation>
</food>

<food>
   <name>noodles</name>
   <preparation time="5">Cooking-Pot</preparation>
</food>

<food>
   <name>lasagne</name>
   <preparation time="10" condition="noodles">Toaster</preparation>
</food>

I need to define that the attribute "condition" can only be used, when the attribute "time" is present. So a element like the following should be invalid:

<food>
   <name>toast</name>
   <preparation condition="noodles">Toaster</preparation>
</food>

Furthermore, the attribute "condition" should only be able to have a value from the element "name" or "device" (and I don't know, if I solved that one since I cannot solve the first demand).

So far I tried defining both demands with an assert. But sadly it is not working at all. Either the attribute "condition" can be used any time and given any random value so it is ignoring all restrictions. Or the compiler (I'm working with Oxygen XML-Editor) always throws an error (Assertion evaluation for element 'food' ond schema type '#AnonType_foodmenues' did not succeed). Here is the example of my xsd-file as it is for further analysis.

XSD:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" vc:minVersion="1.1"> 
    <xs:element name="menues">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="food" maxOccurs="unbounded" minOccurs="0">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="name">
                                <xs:simpleType>
                                    <xs:restriction base="xs:string">
                                        <xs:enumeration value="tea"/>
                                        <xs:enumeration value="sandwich"/>
                                        <xs:enumeration value="noodles"/>
                                        <xs:enumeration value="lasagne"/>
                                        <xs:enumeration value="pizza"/>
                                        <xs:enumeration value="juice"/>
                                        <xs:enumeration value="salat"/>
                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:element>
                            <xs:element name="preparation">
                                <xs:complexType>
                                    <xs:simpleContent>
                                        <xs:extension base="device">
                                            <xs:attribute name="time">
                                                <xs:simpleType>
                                                    <xs:restriction base="xs:integer"/>
                                                </xs:simpleType>
                                            </xs:attribute>
                                            <xs:attribute name="condition" type="xs:string"/>
                                        </xs:extension>
                                    </xs:simpleContent>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                        <xs:assert test="(preparation/@condition = (name, device)) or not (preparation/@condition)"/>
                        <xs:assert test="if (@condition) then (@time) else not (@condition)"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="device">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Ready to Go"/>
            <xs:enumeration value="Toaster"/>
            <xs:enumeration value="Cooking-Pot"/>
            <xs:enumeration value="Pan"/>
            <xs:enumeration value="Ofen"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

Where did I make the mistake? Since this is not working, I assume my asserts are wrong but I wasn't able to figure out if they were missplaced or if they are written wrong. How do I make it that the attribute "condition" can only be used when the attribute "time" is present? Any help is greatly appreciated.


Solution

  • I was able to figure it out: I just had to slightly change the asserts. The first one was to be changed to <xs:assert test="(@time) or not (@condition)"/> in order to only allow the attribute "condition" to be used when "time" is present. The second one I could delete by generalizing the attribute "name" to a type-definition and rewriting the "condition"-attributes type in a xs:union like this:

    <xs:attribute name="condition">
       <xs:simpleType>
          <xs:union memberTypes="name device"/>
       </xs:simpleType>
    </xs:attribute>