1

I am trying to restrict elements inside a choice element with minOccurs and maxOccurs, but it doesn't look like it is working.

I created a choice and tried to restrict "person" to 1 occurence max, and "address" to 1 occurence min, but when I try to validate a XML file containing 2 occurences of "person" and 0 occurence of "address", the validator I use (Xerces) says it is valid.

Is what I am trying to do correct? Is there any way to force the occurence of an element inside a choice?

Here are my XSD and XML :

mySchema.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="family">
    <xs:complexType>
        <xs:choice maxOccurs="unbounded">
            <xs:element name="person" maxOccurs="1">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="name" type="xs:string"/>
                        <xs:element name="firstname" type="xs:string"/>
                        <xs:element name="age" type="xs:int"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
            <xs:element name="address" type="xs:string" minOccurs="1"/> 
        </xs:choice>
    </xs:complexType>
</xs:element>

</xs:schema>

instance.xml

<?xml version="1.0" encoding="UTF-8"?>
<family>
    <person>
        <name> Kurtis </name>
        <firstname> John </firstname>
        <age> 35 </age>
    </person>
    <person>
        <name> Kurtis </name>
        <firstname> Helena </firstname>
        <age> 33 </age>
    </person>
</family>
dan1st
  • 12,568
  • 8
  • 34
  • 67
realUser404
  • 2,111
  • 3
  • 20
  • 38

1 Answers1

3

Actually <xs:element name="person" maxOccurs="1"> should be unnecessary and <xs:element name="person"> should be enougn.

<xs:choice maxOccurs="unbounded"> is reason why two person are evaluated as ok, just try <xs:choice>.

In <xs:element name="address" type="xs:string" minOccurs="1"/> you should add maxOccurs attribute <xs:element name="address" type="xs:string" minOccurs="1" maxOccurs="unbounded" />

Edit:

You could make something like this:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="family">
        <xs:complexType>
            <!-- Choice between one "person" element and one or more "address" element. They cannot occur simultaneously because of choice -->
            <xs:choice>
                <xs:element name="person">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="name" type="xs:string"/>
                            <xs:element name="firstname" type="xs:string"/>
                            <xs:element name="age" type="xs:int"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="address" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>
</xs:schema>

In this case xml with one person will validate

<?xml version="1.0" encoding="UTF-8"?>
<family xsi:noNamespaceSchemaLocation="Untitled4.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <person>
        <name>String</name>
        <firstname>String</firstname>
        <age>0</age>
    </person>
</family>

or xml with many address elements will validate

<?xml version="1.0" encoding="UTF-8"?>
<family xsi:noNamespaceSchemaLocation="Untitled4.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <address>a</address>
    <address>b</address>
    <address>c</address>
</family>

XML with two persons won't validate as well as XML with one person and some address elements (because of choice structure).

If you needed have both person and address elements in one XML you should change choice into sequence like following

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="family">
        <xs:complexType>
            <xs:sequence>
                <!-- Only 0 or 1 "person element might appear -->
                <xs:element name="person" minOccurs="0">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="name" type="xs:string"/>
                            <xs:element name="firstname" type="xs:string"/>
                            <xs:element name="age" type="xs:int"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <!-- followed by many "address" elements -->
                <xs:element name="address" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

so e.g. following xml will validate

<?xml version="1.0" encoding="UTF-8"?>
<family xsi:noNamespaceSchemaLocation="Untitled4.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <person>
        <name>String</name>
        <firstname>String</firstname>
        <age>0</age>
    </person>
    <address>String</address>
    <address>String</address>
    <address>String</address>
</family>

as well as

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

I previous example there could be only 0 or 1 "person" element and it had to be first of all elements since sequence enforce this order.

If you needed address elements could precede person element you would need change the model to all. But unfortunately at this model you cannot have more occurences of one elements so you should "wrap" address elements into another one like

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="family">
        <xs:complexType>
            <xs:all>
                <!-- Only 0 or 1 "person element might appear -->
                <xs:element name="person" minOccurs="0">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="name" type="xs:string"/>
                            <xs:element name="firstname" type="xs:string"/>
                            <xs:element name="age" type="xs:int"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <!-- or many "address" elements packed into "addresses" element-->
                <xs:element name="addresses">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="address" type="xs:string" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:all>
        </xs:complexType>
    </xs:element>
</xs:schema>

In this case following XMLs will validate

Example 1

<?xml version="1.0" encoding="UTF-8"?>
<family xsi:noNamespaceSchemaLocation="Untitled4.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <person>
        <name>String</name>
        <firstname>String</firstname>
        <age>0</age>
    </person>
    <addresses>
        <address>String</address>
        <address>String</address>
        <address>String</address>
    </addresses>
</family>

Example 2

<?xml version="1.0" encoding="UTF-8"?>
<family xsi:noNamespaceSchemaLocation="Untitled4.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <addresses>
        <address>String</address>
        <address>String</address>
        <address>String</address>
    </addresses>
    <person>
        <name>String</name>
        <firstname>String</firstname>
        <age>0</age>
    </person>
</family>

Example 3

<?xml version="1.0" encoding="UTF-8"?>
<family xsi:noNamespaceSchemaLocation="Untitled4.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <addresses>
        <address>String</address>
        <address>String</address>
        <address>String</address>
    </addresses>
</family>
Jirka Š.
  • 3,388
  • 2
  • 15
  • 17
  • This is actually just an example to illustrate my question. What I want is a choice which can contain maximum 1 person, and at least one address (or the opposite, which would make more sense). – realUser404 Oct 14 '13 at 14:06
  • Ok... I'm still not sure what exactly you are trying to do but I added some hints into my answer. Take a look if some of them might be useful for you. – Jirka Š. Oct 14 '13 at 15:20
  • What I understand is that if I absolutely want an "address" element in my XML, I need to use a sequence and not a choice. Is that correct? – realUser404 Oct 15 '13 at 07:23
  • Yes, assuming there is no problem with fixed order of elements defined in that sequence. – Jirka Š. Oct 15 '13 at 07:38
  • So if I don't want to force the order of the elements, but still want to force the presence of an element, there is no way of doing that? – realUser404 Oct 15 '13 at 07:57
  • You can use `` - but it is limited by maxOccurence="1" in all elements it contains. – Jirka Š. Oct 15 '13 at 08:00