simple - xsd element example
¿Cómo extender una opción complexType sin secuenciar la elección? (4)
Desafortunadamente, la respuesta corta es NO, no puede extender un compositor de elección. Lógicamente, si hay algún tipo de relación entre a, b y c (como en Java, .NET, todo es un Objeto, podrías hacer lo mismo en XSD), entonces sugiero el uso de grupos de sustitución (o, Si lo prefieres, algo basado en xsi: type).
ACTUALIZAR con un ejemplo. El XSD-1:
<?xml version="1.0" encoding="utf-8" ?>
<!--W3C Schema generated by QTAssistant/W3C Schema Refactoring Module (http://www.paschidev.com)-->
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="ab" type="abType"/>
<xsd:complexType name="abType">
<xsd:sequence>
<xsd:element ref="ExtensibleChoice-A" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="ExtensibleChoice-A" type="ExtensibleChoiceBaseType" abstract="true" />
<xsd:complexType name="ExtensibleChoiceBaseType" abstract="true">
<xsd:sequence/>
</xsd:complexType>
<xsd:element name="a" substitutionGroup="ExtensibleChoice-A" type="aType" block="#all"/>
<xsd:element name="b" substitutionGroup="ExtensibleChoice-A" type="bType" block="#all"/>
<xsd:element name="c" substitutionGroup="ExtensibleChoice-A" type="cType" block="#all"/>
<xsd:complexType name="aType">
<xsd:complexContent>
<xsd:extension base="ExtensibleChoiceBaseType">
<xsd:sequence>
<xsd:element name="aChild" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="bType">
<xsd:complexContent>
<xsd:extension base="ExtensibleChoiceBaseType">
<xsd:sequence>
<xsd:element name="bChild" type="xsd:int"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="cType">
<xsd:complexContent>
<xsd:extension base="ExtensibleChoiceBaseType">
<xsd:sequence>
<xsd:element name="cChild" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
La extensibilidad es que, en un momento dado, es posible que tenga solo a , byc como miembros. Si usted, o un consumidor, decide agregar algo (digamos un elemento d ), simplemente cree otro esquema que haga referencia al anterior, con el nuevo elemento d , y luego use ese nuevo esquema. El viejo archivo XSD no se toca; la generación de nuevas clases JAXB (como ejemplo) dará como resultado un código compatible con versiones anteriores.
Entonces, XSD-1 validará algo como esto:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<ab xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
<a>
<aChild>aChild1</aChild>
</a>
<b>
<bChild>1</bChild>
</b>
<c>
<cChild>cChild1</cChild>
</c>
</ab>
Necesitarías algo como esto (XSD-2):
<?xml version="1.0" encoding="utf-8" ?>
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema1.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema1.xsd" xmlns:b="http://tempuri.org/XMLSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="http://tempuri.org/XMLSchema.xsd" schemaLocation="XSD-1.xsd"/>
<xsd:element name="d" substitutionGroup="b:ExtensibleChoice-A" type="dType" block="#all"/>
<xsd:complexType name="dType">
<xsd:complexContent>
<xsd:extension base="b:ExtensibleChoiceBaseType">
<xsd:sequence>
<xsd:element name="dChild" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
- El diagrama muestra la "nueva" lista de miembros, d se resalta en azul:
Para validar esto:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<ab xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:d="http://tempuri.org/XMLSchema1.xsd">
<a>
<aChild>aChild1</aChild>
</a>
<d:d>
<d:dChild>1</d:dChild>
</d:d>
</ab>
Tengo una opción complexType llamada abType
:
<xs:complexType name="abType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="a"/>
<xs:element name="b"/>
</xs:choice>
</xs:complexType>
Este tipo se puede usar para crear elementos con los nodos b
en cualquier orden como este, por ejemplo:
<ab>
<b/>
<a/>
</ab>
Ahora quiero crear un tipo derivado llamado abcType
para permitir los nodos a
, b
y c
en cualquier orden. Por lo tanto, creé un nuevo complexType basado en abType
:
<xs:complexType name="abcType">
<xs:complexContent>
<xs:extension base="abType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="c"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
Después de eso creé un nodo abc
:
<abc>
<c/>
<b/>
<a/>
</abc>
¡Pero este nodo no es válido ! No es válido poner a
o b
después de un c
. La razón es que derivar un tipo a partir de un tipo base crea una secuencia implícita aunque ambos tipos son opciones. XMLspy lo ilustra de esta manera:
Este resultado es bastante inútil para los tipos de elección.
Entonces mi pregunta es: ¿Cómo extender un tipo de elección sin secuenciar la elección?
Aquí está el XSD completo y un archivo de prueba XML para reproducir el problema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="ab"/>
<xs:element ref="abc"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="ab" type="abType"/>
<xs:complexType name="abType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="a"/>
<xs:element name="b"/>
</xs:choice>
</xs:complexType>
<xs:element name="abc" type="abcType"/>
<xs:complexType name="abcType">
<xs:complexContent>
<xs:extension base="abType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="c"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
Ejemplo:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="inherit-choice.xsd">
<ab>
<b/>
<a/>
</ab>
<abc>
<c/>
<b/>
<a/>
</abc>
</root>
Hay una manera de hacer esto que se basa en el hecho de que una elección dentro de una elección actúa como una opción más grande.
Primero, defina un grupo de elementos que contenga una sola opción de todos los elementos dentro del elemento base:
<xs:group name="common_ab_elements">
<xs:choice>
<xs:element name="a"/>
<xs:element name="b"/>
</xs:choice>
</xs:group>
Luego puede usar esto en su definición de AbElement en lugar de los elementos que tenía antes:
<xs:complexType name="abType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="common_ab_elements"/>
</xs:choice>
</xs:complexType>
Si necesita un tipo extendido, puede extender la opción:
<xs:complexType name="abcType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:group ref="common_ab_elements"/>
<xs:element name="c"/>
</xs:choice>
</xs:complexType>
Esto es equivalente a:
<xs:complexType name="abcType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:choice>
<xs:element name="a"/>
<xs:element name="b"/>
</xs:choice>
<xs:element name="c"/>
</xs:choice>
</xs:complexType>
Y debido a la naturaleza de la operación de elección, esto a su vez es equivalente a:
<xs:complexType name="abcType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="a"/>
<xs:element name="b"/>
<xs:element name="c"/>
</xs:choice>
</xs:complexType>
... que es lo que quieres.
Si también tiene atributos, es posible que también deba definir una clase base común que pueda ampliar. Con este esquema, solo las clases sin clases derivadas deben tener elementos, ya que es la presencia de elementos en los elementos base lo que fuerza la secuenciación.
Lo que estamos haciendo efectivamente aquí es definir la herencia de los elementos de elección por separado de la jerarquía de elementos en sí.
Otro ejemplo con sustituciones.
XSD
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="abExtension"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="abExtension" type="abExtensionType"/>
<xs:complexType name="abExtensionType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="a"/>
<xs:element name="b"/>
</xs:choice>
</xs:complexType>
<xs:element name="abcExtension" substitutionGroup="abExtension">
<xs:complexType>
<xs:complexContent>
<xs:extension base="abExtensionType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="c"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="abcdExtension" substitutionGroup="abExtension">
<xs:complexType>
<xs:complexContent>
<xs:extension base="abExtensionType">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="c"/>
<xs:element name="d"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>
Los XML de muestra que se validan con esto son
abcExtension.xml
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test.xsd">
<abcExtension>
<b></b>
<a></a>
<c></c>
</abcExtension>
</root>
abcdExtension.xml
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test.xsd">
<abcdExtension>
<a>text</a>
<b>test</b>
<d>text</d>
<c>text</c>
</abcdExtension>
</root>
abExtension.xml
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test.xsd">
<abExtension>
<b></b>
<a></a>
</abExtension>
</root>
Si su enfoque es extender la herencia en lugar de la herencia de tipos , se puede extender una <choice>
redefiniendo un <group>
siguiente manera:
Archivo "abc.xsd" que contiene el esquema base:
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="any"
xmlns:n="any"
elementFormDefault="qualified">
<group name="baseGroup">
<choice>
<element name="a"/>
<element name="b"/>
<element name="c"/>
</choice>
</group>
<complexType name="choiceType">
<sequence minOccurs="0" maxOccurs="unbounded">
<group ref="n:baseGroup"/>
</sequence>
</complexType>
<element name="test">
<complexType>
<sequence>
<element name="sample" type="n:choiceType" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
</schema>
El archivo "abcdef.xsd" extiende la <choice>
definida en el esquema base:
<?xml version="1.0"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="any"
xmlns:n="any"
elementFormDefault="qualified">
<redefine schemaLocation="abc.xsd">
<group name="baseGroup">
<choice>
<group ref="n:baseGroup"/>
<element name="d"/>
<element name="e"/>
</choice>
</group>
</redefine>
</schema>
Esto valida el siguiente archivo xml, por ejemplo:
<?xml version="1.0" encoding="UTF-8"?>
<test
xmlns="any"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="any ../schemas/abcde.xsd">
<sample>
<a/>
<c/>
<b/>
<a/>
</sample>
<sample>
<c/>
</sample>
<sample>
</sample>
<sample>
<a/>
<e/>
<b/>
<d/>
<a/>
</sample>
</test>