1
votes

I am working on an XML Schema (message.xsd) describing the structure of a message.

Here are the expected children of the <message> element (the root):

  • <from>: Contains the address of the sender. Occurs 0 or 1 times.
  • <to>: Contains the address of the recipient. Occurs 0 or more times.
  • <cc>: Contains the address of the recipient in copy. Occurs 0 or more times.
  • <subject>: Contains the subject of the message. Occurs 0 or 1 times.
  • <body>: Contains the body of the message. Occurs 0 or 1 times.

The order of elements does not matter, it means that they can be in any order.

Here is a first simple XML example (message-1.xml) that has to be valid:

$ xmllint --schema message.xsd message-1.xml 
<?xml version="1.0"?>
<message xmlns="http://yugiohjcj.1s.fr/message">
    <from>[email protected]</from>
    <to>[email protected]</to>
    <subject>How are you?</subject>
    <body>Hello. How are you? Thank you. Best regards.</body>
</message>
message-1.xml validates

And it is valid!

Here is a second more complex XML example (message-2.xml) that has to be valid:

$ xmllint --schema message.xsd message-2.xml 
<?xml version="1.0"?>
<message xmlns="http://yugiohjcj.1s.fr/message">
    <subject>How are you?</subject>
    <body>Hello. How are you? Thank you. Best regards.</body>
    <from>[email protected]</from>
    <to>[email protected]</to>
    <to>[email protected]</to>
    <cc>[email protected]</cc>
    <cc>[email protected]</cc>
</message>
message-2.xml validates

And it is valid!

Here is a third XML example (message-3.xml) that has to be not valid:

$ xmllint --schema message.xsd message-3.xml 
<?xml version="1.0"?>
<message xmlns="http://yugiohjcj.1s.fr/message">
    <from>[email protected]</from>
    <from>[email protected]</from>
    <to>[email protected]</to>
    <subject>How are you?</subject>
    <subject>How are you again?</subject>
    <body>Hello. How are you? Thank you. Best regards.</body>
    <body>Hello. How are you again? Thank you. Best regards.</body>
</message>
message-3.xml validates

But it is valid! That's the problem.

Here is my XML Schema (message.xsd):

$ cat message.xsd 
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://yugiohjcj.1s.fr/message" targetNamespace="http://yugiohjcj.1s.fr/message" elementFormDefault="qualified">
    <xs:element name="message">
        <xs:complexType>
            <xs:sequence>
                <xs:choice minOccurs="0" maxOccurs="unbounded">
                    <xs:element name="from"/>
                    <xs:element name="to"/>
                    <xs:element name="cc"/>
                    <xs:element name="subject"/>
                    <xs:element name="body"/>
                </xs:choice>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

I guess that I need to set the maxOccurs attribute to the value 1 somewhere or maybe I need to combine differently the <xs:sequence> and <xs:choice> elements but I have not found how to reach my goal.

Any idea how to fix this XML Schema please?

Thank you.

Best regards.


Edit: OK I found a workaround to my problem by using Relax NG instead of XSD 1.0. It works fine and it is compatible with libxml2.

Here is my message.rng file:

$ cat message.rng 
<element name="message" xmlns="http://relaxng.org/ns/structure/1.0">
    <interleave>
        <zeroOrMore>
            <element name="from">
                <text/>
            </element>
        </zeroOrMore>
        <zeroOrMore>
            <element name="to">
                <text/>
            </element>
        </zeroOrMore>
        <zeroOrMore>
            <element name="cc">
                <text/>
            </element>
        </zeroOrMore>
        <optional>
            <element name="subject">
                <text/>
            </element>
        </optional>
        <optional>
            <element name="body">
                <text/>
            </element>
        </optional>
    </interleave>
</element>

And here is the result on my 3 XML examples (message-1.xml, message-2.xml and message-3.xml):

$ xmllint --relaxng message.rng message-1.xml 
<?xml version="1.0"?>
<message>
    <from>[email protected]</from>
    <to>[email protected]</to>
    <subject>How are you?</subject>
    <body>Hello. How are you? Thank you. Best regards.</body>
</message>
message-1.xml validates
$ xmllint --relaxng message.rng message-2.xml 
<?xml version="1.0"?>
<message>
    <subject>How are you?</subject>
    <body>Hello. How are you? Thank you. Best regards.</body>
    <from>[email protected]</from>
    <to>[email protected]</to>
    <to>[email protected]</to>
    <cc>[email protected]</cc>
    <cc>[email protected]</cc>
</message>
message-2.xml validates
$ xmllint --relaxng message.rng message-3.xml 
<?xml version="1.0"?>
<message>
    <from>[email protected]</from>
    <from>[email protected]</from>
    <to>[email protected]</to>
    <subject>How are you?</subject>
    <subject>How are you again?</subject>
    <body>Hello. How are you? Thank you. Best regards.</body>
    <body>Hello. How are you again? Thank you. Best regards.</body>
</message>
Relax-NG validity error : Extra element subject in interleave
message-3.xml:7: element subject: Relax-NG validity error : Element message failed to validate content
message-3.xml fails to validate
1

1 Answers

0
votes

In XSD 1.0 if you want to allow elements to appear in any order then the only way to control how often each element may appear is using xs:all, and this constrains the number of appearances to be zero or one. So you can't achieve what you are attempting.

This restriction is lifted in XSD 1.1.