XML Schema Key with multiple fields

schema, xml, xsd

Solution

Alright, I found this question (XSD key/keyref: hierarchical key structure) that related to my question. That question didn't have an acceptable answer either.

It appears that this is a limitation of XML Schema technology. I decided to reorder the Schema, to put the user's responses under the question. The responses would then refer to the user.

Below is the example XML Instance:

<?xml version="1.0" encoding="utf-8"?>
<survey>
  <user id="bob" />
  <user id="jane" />
  <question id="q101">
    <text>Do you like the color red?</text>
    <answer>yes</answer>
    <answer>no</answer>
    <response userIdRef="bob">yes</response>
    <response userIdRef="jane">no</response>
  </question>
  <question id="q102">
    <text>What is your favorite color?</text>
    <answer>red</answer>
    <answer>blue</answer>
    <answer>white</answer>
    <answer>yellow</answer>
    <response userIdRef="bob">white</response>
    <response userIdRef="jane">blue</response>
  </question>
</survey>

Here is the Schema I used:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="survey">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="user" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string" use="required" />
          </xsd:complexType>
        </xsd:element>
        <xsd:element name="question" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="text" type="xsd:string" />
              <xsd:element name="answer" maxOccurs="unbounded" type="xsd:string"/>
              <xsd:element name="response" maxOccurs="unbounded">
                <xsd:complexType>
                  <xsd:simpleContent>
                    <xsd:extension base="xsd:string">
                      <xsd:attribute name="userIdRef" type="xsd:string" use="required" />
                    </xsd:extension>
                  </xsd:simpleContent>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
            <xsd:attribute name="id" type="xsd:string" use="required" />
          </xsd:complexType>
          <xsd:key name="validAnswerKey">
            <xsd:selector xpath=".//answer" />
            <xsd:field xpath="." />
          </xsd:key>
          <xsd:keyref name="responseValidAnswerKeyRef" refer="validAnswerKey">
            <xsd:selector xpath=".//response" />
            <xsd:field xpath="." />
          </xsd:keyref>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
    <xsd:key name="userIdKey">
      <xsd:selector xpath=".//user" />
      <xsd:field xpath="@id" />
    </xsd:key>
    <xsd:keyref name="userResponse" refer="userIdKey">
      <xsd:selector xpath=".//response" />
      <xsd:field xpath="@userIdRef" />
    </xsd:keyref>
  </xsd:element>
</xsd:schema>

Problem

I have an XML file format that contains a structure of questions: ``` <question id="q101"> <text>Do you like the color red?</text> <answer>yes</answer> <answer>no</answer> </question> <question id="q102"> <text>What is your favorite color?</text> <answer>red</answer> <answer>blue</answer> <answer>white</answer> <answer>yellow</answer> </question> ``` I also have in the same file responses from multiple users. ``` <user id="bob"> <response questionIdRef="q101">yes</response> <response questionIdRef="q102">white</response> </user> <user id="jane"> <response questionIdRef="q101">no</response> <response questionIdRef="q102">blue</response> </user> ``` I have already defined in the xml a key and a keyref element for the questionId: ``` <xsd:key name="questionId"> <xsd:selector xpath=".//question" /> <xsd:field xpath="@id" /> </xsd:key> <xsd:keyref name="responseQuestionIdKeyRef" refer="questionId"> <xsd:selector xpath=".//response" /> <xsd:field xpath="@questionIdRef" /> </xsd:keyref> ``` What I would like to do now would be to do is now have the schema verify that value of the user's response for a certain question is actually an answer provided in the referenced question. I tried to do this with the following key and keyref, but it would only recognize the first answer, all other answers were not recognized as valid: ``` <xsd:key name="answerValue"> <xsd:selector xpath=".//question" /> <xsd:field xpath="@id" /> <xsd:field xpath=".//answer/value" /> </xsd:key> <xsd:keyref name="validAnswer" refer="answerValue"> <xsd:selector xpath=".//response" /> <xsd:field xpath="@questionIdRef" /> <xsd:field xpath="." /> </xsd:keyref> ``` The exact error I am getting is: The field 'answer' is expecting at most one value. I should note that I am using C# XML validator. For completeness, below is the complete schema and xml instance I am referring to: Schema: ``` <?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="survey"> <xsd:complexType> <xsd:sequence> <xsd:element name="user" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="response" maxOccurs="unbounded"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="questionIdRef" type="xsd:string" use="required" /> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> <xsd:attribute name="id" type="xsd:string" use="required" /> </xsd:complexType> </xsd:element> <xsd:element name="question" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="text" type="xsd:string" /> <xsd:element name="answer" maxOccurs="unbounded" type="xsd:string"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:string" use="required" /> </xsd:complexType> <xsd:unique name="uniqueAnswer"> <xsd:selector xpath=".//answer" /> <xsd:field xpath="@value" /> </xsd:unique> </xsd:element> </xsd:sequence> </xsd:complexType> <!-- <xsd:key name="questionId"> <xsd:selector xpath=".//question" /> <xsd:field xpath="@id" /> </xsd:key> <xsd:keyref name="responseQuestionIdKeyRef" refer="questionId"> <xsd:selector xpath=".//response" /> <xsd:field xpath="@questionIdRef" /> </xsd:keyref> --> <xsd:key name="answerValue"> <xsd:selector xpath=".//question" /> <xsd:field xpath="@id" /> <xsd:field xpath=".//answer" /> </xsd:key> <xsd:keyref name="validAnswer" refer="answerValue"> <xsd:selector xpath=".//response" /> <xsd:field xpath="@questionIdRef" /> <xsd:field xpath="." /> </xsd:keyref> <xsd:unique name="uniqueUserId"> <xsd:selector xpath=".//user" /> <xsd:field xpath="@id" /> </xsd:unique> </xsd:element> </xsd:schema> ``` Sample XML Instance: ``` <?xml version="1.0" encoding="utf-8"?> <survey> <user id="bob"> <response questionIdRef="q101">yes</response> <response questionIdRef="q102">white</response> </user> <user id="jane"> <response questionIdRef="q101">no</response> <response questionIdRef="q102">blue</response> </user> <question id="q101"> <text>Do you like the color red?</text> <answer>yes</answer> <answer>no</answer> </question> <question id="q102"> <text>What is your favorite color?</text> <answer>red</answer> <answer>blue</answer> <answer>white</answer> <answer>yellow</answer> </question> </survey> ```

Original source

Related problems