-->

Nested choice element in XML Schema?

2019-05-11 20:01发布

问题:

What I'm trying to do is, declare an parent element called "data", which are having 6 sub element of these two element are conditional that means if element A is choose then B is not appear in "data".

Like this:

<data>
   <A>text1</A>
   <B>text1</B>
   <C>text1</C>
   <D>text1</D>

   <E>text1</E> or <F>text1</F>

</data>

Requirement 1 : all element can appear in any order and any number of times.

Requirement 2 : Element E & F are conditional means only one of then is apear in data.

My xsd code is this:

<xs:element name="data">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="sequence" minOccurs="0" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:choice minOccurs="0" maxOccurs="unbounded" >
                            <xs:element ref="A" />
                            <xs:element ref="B" />
                            <xs:element ref="C" />
                            <xs:element ref="D" />                          
                            <xs:choice>
                                <xs:element ref="E" />
                                <xs:element ref="F" />
                                <xs:element ref="G" />
                            </xs:choice>
                        </xs:choice>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:attribute name="status"/>
        </xs:complexType>
    </xs:element>

I have tried all these link but still not getting my solution.

XSD - how to allow elements in any order any number of times?

Nested sequence in XSD

XSD nested element

回答1:

Your are running afoul of a constraint on content models known variously as the "ambiguity rules" (in SGML), the "determinism rules" (so called in XML, which declined to call them ambiguity rules because in fact what is forbidden is not actually ambiguity, but non-determinism of the finite state automaton formed in a particular way from the content model), or the "unique particle attribution rules" (so called because the lead editor of XSD 1.0 appears to have thought they were different in some way from the determinism rules of XML; I've forgotten what the difference was supposed to be, and only remember that it was based on a misunderstanding of the XML rules). They don't actually have a good technical motivation (they were a design error in SGML, carried forward into XML for compatibility reasons and into XSD for no good reason at all), and (as you have found) they complicate the construction of legal content models, which is one reason some people are so happy with Relax NG, which mostly eliminates them. But since for better or worse they are part of so many languages for XML document grammars, it is worth knowing how to comply with them.

The language you describe is: any sequence of A, B, C, or D elements, intermixed either with E elements or with F elements. To describe this language in a deterministic content model, you may find it helpful to think about what different states an automaton would have to have, in order to recognize such a language. In one state, any of the elements A to F is legal. Elements A through D leave us in that state. But once we see an E or an F, we move into a different state, in which A through D and either E or F (whichever we saw first) is legal, but the other (F or E) is not accepted. So we need three states.

Note that each state corresponds to a language of its own: the sequence of elements we can see that put us into that state and leave us in that state. If we name the states initial, eee, and eff, we can summarize the languages with a regular expression which is easily translated into XSD:

  • L(initial) = (A|B|C|D)*
  • L(eee) = E, (A|B|C|D|E)*
  • L(eff) = F, (A|B|C|D|F)*

Note that from the first state, we can move to the second or the third, but once we are in either of those states, we never leave it. This means that the language we want is effectively L(initial) followed by a choice of L(eee) or L(eff). So one XSD formulation would be:

<xsd:group name="initial">
  <xsd:sequence>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="A"/>
      <xsd:element ref="B"/>
      <xsd:element ref="C"/>
      <xsd:element ref="D"/>
    </xsd:choice>      
  </xsd:sequence>    
</xsd:group>
<xsd:group name="eee">
  <xsd:sequence>
    <xsd:sequence minOccurs="0">
      <xsd:element ref="E"/>
      <xsd:choice minOccurs="0" maxOccurs="unbounded">
        <xsd:element ref="A"/>
        <xsd:element ref="B"/>
        <xsd:element ref="C"/>
        <xsd:element ref="D"/>
        <xsd:element ref="E"/>
      </xsd:choice>
    </xsd:sequence>
  </xsd:sequence>    
</xsd:group>
<xsd:group name="eff">
  <xsd:sequence minOccurs="0">
    <xsd:element ref="F"/>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="A"/>
      <xsd:element ref="B"/>
      <xsd:element ref="C"/>
      <xsd:element ref="D"/>
      <xsd:element ref="F"/>
    </xsd:choice>
  </xsd:sequence>
</xsd:group>
<xsd:complexType name="data">
  <xsd:sequence>
    <xsd:group ref="initial"/>
    <xsd:choice>
      <xsd:group ref="eee"/>
      <xsd:group ref="eff"/>
    </xsd:choice>
  </xsd:sequence>
</xsd:complexType>
<xsd:element name="data" type="data"/>

This amounts to describing your language in a different way: a sequence of A, B, C, or D elements, followed optionally either by an E and then any sequence of A, B, C, D, or E elements, or by an F and then any sequence of A, B, C, D, or F elements. It is worth spending as much time as it takes to persuade yourself that the language so described is the same as the language you describe in your description of the problem.



回答2:

So it's a choice between (A|B|C|D|E)* and (A|B|C|D|F)* - you can factor out the common A|B|C|D part into a group:

<xs:group name="commonElements">
  <xs:choice>
    <xs:element ref="A" />
    <xs:element ref="B" />
    <xs:element ref="C" />
    <xs:element ref="D" />
  </xs:choice>
</xs:group>

<xs:element name="data">
  <xs:complexType>
    <xs:choice>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:group ref="commonElements" />
        <xs:element ref="E" />
      </xs:choice>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:group ref="commonElements" />
        <xs:element ref="F" />
      </xs:choice>
    </xs:choice>
  </xs:complexType>
</xs:element>

This will allow any mixture of A, B, C, D, E, F in any order, except that it won't allow any Es if there is an F or vice-versa.