pattern - xml schema simple
Cómo crear un esquema para una lista desordenada de nodos XML, con restricciones de ocurrencia (3)
Dado un diseño XML como este, estoy intentando crear un esquema XSD para validarlo.
<RootNode>
<ChildA />
<ChildC />
<ChildB />
<ChildB />
<ChildA />
</RootNode>
Los requisitos son los siguientes:
- ChildA, ChildB y ChildC pueden aparecer en cualquier orden . (
<xs:sequence>
inadecuada) - ChildA es obligatorio pero puede ocurrir varias veces.
- ChildB es opcional y puede ocurrir varias veces.
- ChildC es opcional y puede ocurrir solo una vez .
La técnica que suelo usar para crear una lista desordenada de nodos es usar una <xs:choice maxOccurs="unbounded">
con cada nodo posible en la lista, sin embargo, no puedo crear la minOccurs="1"
en ChildA y la maxOccurs="1"
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>
Estaba leyendo la sintaxis de acceso directo de relax-NG .
Supongo que esto se condensaría a lo siguiente en la sintaxis compacta de relax-ng:
head = element root { ChildA & ChildC? & ChildB* }
Eso seguro es bonito.
Esto debería hacer lo que especificaste:
<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>
Actualización : En XSD 1.1m, algunas de las restricciones en all
grupos se han eliminado. 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í, el uso de algún otro sistema de validación probablemente hubiera proporcionado una respuesta más simple.
He hecho algunas pruebas, pero perdiendo algunos casos especiales es fácil. Por favor comenta si ves 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>