2010-08-01 14 views
16

Dado un diseño XML como este, intento crear un esquema XSD para validarlo.Cómo crear un esquema para una lista desordenada de nodos XML, con restricciones de ocurrencia

<RootNode> 
    <ChildA /> 
    <ChildC /> 
    <ChildB /> 
    <ChildB /> 
    <ChildA /> 
</RootNode> 

Los requisitos son los siguientes:

  • Childa, Parto de y ChildC puede ocurrir en cualquier orden. (<xs:sequence> no adecuado)
  • ChildA es obligatorio pero puede aparecer varias veces.
  • ChildB es opcional y puede aparecer varias veces.
  • ChildC es opcional y puede ocurrir una vez solo.

La técnica que suelen utilizar para crear una lista no ordenada de nodos es utilizar un <xs:choice maxOccurs="unbounded"> con cada posible nodo en la lista, sin embargo, Soy incapaz de crear la restricción en Childa y la maxOccurs="1" contraint en ChildC. (El número de ocurrencias de la elección tiene prioridad sobre las de los elementos aquí).

<xs:element name="RootNode"> 
    <xs:complexType> 
    <xs:choice minOccurs="1" maxOccurs="unbounded"> 
     <xs:element name="ChildA" minOccurs="1"/> 
     <xs:element name="ChildB" /> 
     <xs:element name="ChildC" maxOccurs="1"/> 
    </xs:choice> 
    </xs:complexType> 
</xs:element> 
+0

no creo que el esquema XML actual es capaz de hacer esto en este momento. ¿Has registrado otros sistemas de validación, como RelaxNG (www.relaxng.org) tal vez? –

+0

Pregunta relacionada con, en el momento de escribir esto, mejores respuestas: https://stackoverflow.com/questions/2290360/xsd-how-to-allow-elements-in-any-order-any-number-of-times/12012599 – Flow

Respuesta

10

actualización: En 1.1m XSD algunas de las limitaciones de all -grupos se han levantado. Vea las respuestas here y here.

No es simple, pero parece factible. La parte difícil aquí es que las definiciones de esquema deben ser deterministas. El enfoque que utilicé fue visualizar el problema dibujando un autómata de estados finitos y luego escribir una expresión regular que correspondiera a ese autómata. No es en absoluto tan complicado como podría parecer. Aún así, usar algún otro sistema de validación probablemente habría proporcionado una respuesta más simple.

He hecho algunas pruebas, pero perder algunos casos especiales es fácil. Comente si detecta un error.

... y aquí está el código:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" > 

    <!-- Schema for elements ChildA, ChildB and ChildC 
     The requirements are as follows: 
      * ChildA, ChildB and ChildC may occur in any order. 
      * ChildA is mandatory but may occur multiple times. 
      * ChildB is optional and may occur multiple times. 
      * ChildC is optional and may occur once only. 
    --> 

    <xsd:element name="root"> 
     <xsd:complexType> 
      <xsd:sequence> 
       <xsd:element name="ABC-container" type="ABC" maxOccurs="unbounded"/> 
      </xsd:sequence> 
     </xsd:complexType> 
    </xsd:element> 

    <xsd:complexType name="ABC"> 
     <xsd:sequence> 
      <xsd:element name="ChildB" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> 
      <xsd:choice> 
       <xsd:sequence maxOccurs="1"> 
        <xsd:element name="ChildC" type="xsd:string"/> 
        <xsd:element name="ChildB" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> 
        <xsd:element name="ChildA" type="xsd:string"/> 
        <xsd:sequence minOccurs="0" maxOccurs="unbounded"> 
         <xsd:element name="ChildA" type="xsd:string" minOccurs="0"/> 
         <xsd:element name="ChildB" type="xsd:string" minOccurs="0"/> 
        </xsd:sequence> 
       </xsd:sequence> 
       <xsd:sequence maxOccurs="1"> 
        <xsd:element name="ChildA" type="xsd:string" minOccurs="1"/> 
        <xsd:sequence minOccurs="0" maxOccurs="unbounded"> 
         <xsd:element name="ChildA" type="xsd:string" minOccurs="0"/> 
         <xsd:element name="ChildB" type="xsd:string" minOccurs="0"/> 
        </xsd:sequence> 
        <xsd:sequence minOccurs="0" maxOccurs="1"> 
         <xsd:element name="ChildC" type="xsd:string"/> 
         <xsd:sequence minOccurs="0" maxOccurs="unbounded"> 
          <xsd:element name="ChildA" type="xsd:string" minOccurs="0"/> 
          <xsd:element name="ChildB" type="xsd:string" minOccurs="0"/> 
         </xsd:sequence> 
        </xsd:sequence> 
       </xsd:sequence> 
      </xsd:choice> 
     </xsd:sequence> 
    </xsd:complexType> 

</xsd:schema> 
+5

"Al combinar y anidar los diversos grupos proporcionados por XML Schema, y ​​al establecer los valores de' minOccurs y maxOccurs', es posible representar cualquier modelo de contenido expresable con un XML 1.0 DTD. " Pero nunca dijeron que sería bonito. – Will

+0

Jasso.Esto es muy inteligente. Estoy tratando de modificarlo para proporcionar: ningún elemento obligatorio (pierda ChildA); y muchos ítems de 0 o 1 aparición (como ChildC). Estoy teniendo un problema real. He publicado la pregunta en http://stackoverflow.com/questions/14321579/how-to-make-a-schema-for-an-unordered-list-where-some-occur-once-some-many-time . Usted parece ser un experto en esto. Si pudieras echarle un vistazo, lo agradecería. – Dave

+0

@Dave Gracias por apreciar mis esfuerzos. Escribí una respuesta a tu pregunta. Llegó un poco tarde, porque no había iniciado sesión aquí durante algunas semanas. – jasso

1

Estaba leyendo el relax-NG shortcut syntax.

supongo esto sería condensarse a la siguiente sintaxis compacto de relax-ng:

head = element root { ChildA & ChildC? & ChildB* } 

Eso es bastante seguro.

+0

Lamento que sea incorrecto ... ya que ChildA es al menos uno, pero puede ser más ... – Texas

+0

'head = element root {ChildA + & ChildC? & ChildB *} '¿quizás? – Alan

2

Esto debería hacer lo especificado:

<xs:element name="RootNode"> 
    <xs:complexType>  
    <xs:all>  
     <xs:element name="ChildA" minOccurs="1"/>  
     <xs:element name="ChildB" />  
     <xs:element name="ChildC" minOccurs="0" maxOccurs="1"/>  
    </xs:all> 
    </xs:complexType> 
</xs:element> 
+0

Gracias por intentarlo, pero esto no encaja del todo. A y B pueden aparecer varias veces, pero el elemento '' especifica que cada elemento puede aparecer cero o solo una vez. Sería bueno si hubiera una solución tan simple como esta, pero creo que la solución de jasso es probablemente la mejor que obtendremos. –

+1

¿Qué sucede si establece minOccurs = 1 y maxOccurs = 1 para todos los elementos secundarios? –

+0

Esa respuesta es correcta (AFAIKT) si usa [XSD 1.1] (https://www.w3.org/TR/xmlschema11-1/). [G1.3 5.] (https://www.w3.org/TR/xmlschema11-1/#changes) explica la diferencia entre XSD 1.0 que permite esto. – Flow

Cuestiones relacionadas