Search code examples
.netxmlxsdxml-validation

Complex XML validation with XSD


Suppose I have the following XML, how should I update my XSD schema (described below as well) to prevent it's validation?

Basically, for question #3, it looks like its a single choice question as there is only one answer in the tag. But then there must be at least one tag inside the tag otherwise there is no other question available to select but the correct one.

<?xml version="1.0" encoding="utf-8" ?>
<quiz>
  <question><!-- single choice question -->
    <text>Question 1</text>
    <answers>
      <answer>Answer 1</answer>
      <answer>Answer 2</answer>
      <answer>Answer 4</answer>
      <correct>
        <answer>Answer 3</answer>
      </correct>
    </answers>
  </question>
  <question><!-- multiple choice question -->
    <text>Question 2</text>
    <answers>
      <answer>Answer 1</answer>
      <answer>Answer 3</answer>
      <correct>
        <answer>Answer 2</answer>
        <answer>Answer 4</answer>
      </correct>
    </answers>
  </question>
  <question><!-- doesn't make sense. help me prevent this validation -->
    <text>Question 3</text>
    <answers>
      <correct>
        <answer>Some answer</answer>
      </correct>
    </answers>
  </question>
  <question><!-- all answers are correct -->
    <text>Question 4</text>
    <answers>
      <correct>
        <answer>Answer 1</answer>
        <answer>Answer 2</answer>
        <answer>Answer 3</answer>
        <answer>Answer 4</answer>
      </correct>
    </answers>
  </question>
</quiz>

Here is the XSD:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="quiz">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="question">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="text" type="xs:string" />
              <xs:element name="answers">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element minOccurs="0" maxOccurs="unbounded" 
                     name="answer" type="xs:string" />
                    <xs:element name="correct" minOccurs="1" maxOccurs="1">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element maxOccurs="unbounded" name="answer"
                           type="xs:string" />
                        </xs:sequence>
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Solution

  • The definition of the answer element (\question\answers\answer), should have minOccurs = 1. You originally had this:

    <xs:element minOccurs="0" maxOccurs="unbounded" name="answer" type="xs:string" />
    

    Change it to this and you'll get the validation you're looking for:

    <xs:element minOccurs="1" maxOccurs="unbounded" name="answer" type="xs:string" />
    

    However, if you're looking to validate that the correct sequence has more than one answer listed when there are no "incorrect" answer elements listed in the answers sequence - you're out of luck. You cannot do that type of validation using XML schemas.