2010-02-18 21 views
92

Estoy tratando de crear un XSD, y tratando de escribir la definición con el siguiente requisito:XSD - cómo permitir elementos en cualquier orden varias veces?

  • Permitir elemento secundario especificado para aparecer cualquier número de veces (de 0 a ilimitada)
  • Permitir elementos secundarios sean en cualquier orden

miré alrededor y encontré varias soluciones como this:

<xs:element name="foo"> 
    <xsl:complexType> 
    <xs:choice minOccurs="0" maxOccurs="unbounded"> 
     <xs:element name="child1" type="xs:int"/> 
     <xs:element name="child2" type="xs:string"/> 
    </xs:choice> 
    </xs:complexType> 
</xs:element> 

Pero por lo que entiendo xs: la opción todavía solo permite la selección de un solo elemento. Por lo tanto, establecer MaxOccurs en este tipo de límites solo debería significar que "cualquiera" de los elementos secundarios puede aparecer varias veces. Es esto exacto?

Si la solución anterior es incorrecta, ¿cómo puedo lograr lo que mencioné anteriormente en mi requerimiento?

EDIT: ¿Qué pasa si el requisito es el siguiente?

  • Elemento child1 child2 puede aparecer cualquier número de veces (0 a ilimitada)
  • Elementos a estar en cualquier orden
  • Elementos Niño3 y Niño4 debería aparecer exactamente una vez.

Por ejemplo, este XML es válido:

<foo> 
<child1> value </child1> 
<child1> value </child1> 
<child3> value </child3> 
<child2> value </child2> 
<child4> value </child4> 
<child1> value </child1> 
</foo> 

pero esto no es (Niño3 faltante)

<foo> 
<child1> value </child1> 
<child1> value </child1> 
<child2> value </child2> 
<child4> value </child4> 
<child1> value </child1> 
</foo> 

Respuesta

48

En el esquema que tiene en su pregunta, child1 o child2 puede aparecer en cualquier orden, cualquier cantidad de veces. Así que esto suena como lo que estás buscando.

Editar: si quería sólo uno de ellos a aparecer un número ilimitado de veces, lo ilimitado tendría que ir sobre los elementos en su lugar:

Editar: tipo fijo en XML.

Editar: O mayúscula que en maxOcurrencias

<xs:element name="foo"> 
    <xs:complexType> 
    <xs:choice maxOccurs="unbounded"> 
     <xs:element name="child1" type="xs:int" maxOccurs="unbounded"/> 
     <xs:element name="child2" type="xs:string" maxOccurs="unbounded"/> 
    </xs:choice> 
    </xs:complexType> 
</xs:element> 
+0

básicamente sí, estoy buscando elementos child1, child2 a aparecer en cualquier orden, cualquier número de veces .. la respuesta que ha proporcionado aquí sólo funciona para un solo elemento, ¿verdad? ¿o esto resuelve mi requisito también? – jvtech

+0

El esquema en su pregunta cumple con su requisito; el esquema alternativo en mi respuesta es para un solo elemento. ¡Espero que eso lo aclare! :) – xcut

+0

@Pavel, @xcut, Gracias por aclarar, ver el requisito editado ... ¿Alguna idea? – jvtech

3

Se debe constatar que el siguiente esquema permite que el lo que usted ha propuesto.

<xs:element name="foo"> 
    <xs:complexType> 
     <xs:sequence minOccurs="0" maxOccurs="unbounded"> 
     <xs:choice> 
      <xs:element maxOccurs="unbounded" name="child1" type="xs:unsignedByte" /> 
      <xs:element maxOccurs="unbounded" name="child2" type="xs:string" /> 
     </xs:choice> 
     </xs:sequence> 
    </xs:complexType> 
    </xs:element> 

Esto le permitirá crear un archivo como:

<?xml version="1.0" encoding="utf-8" ?> 
<foo> 
    <child1>2</child1> 
    <child1>3</child1> 
    <child2>test</child2> 
    <child2>another-test</child2> 
</foo> 

que parece coincidir con su pregunta.

+0

'' minOccurs' y maxOccurs' están restringidos a 1 para los niños de 'xs: all'. –

+0

Pavel: Gracias ... me encontré con esto después de doble control de mi puesto y luego lo editó para eliminar los xs: –

8

Pero por lo que entiendo xs: la opción todavía solo permite la selección de un solo elemento.Por lo tanto, establecer MaxOccurs en este tipo de límites solo debería significar que "cualquiera" de los elementos secundarios puede aparecer varias veces. Es esto exacto?

No. La elección ocurre de forma individual para cada "repetición" de xs:choice que se produce debido a maxOccurs="unbounded". Por lo tanto, el código que ha publicado es correcto, y realmente hará lo que quiera tal como está escrito.

+0

toda su comentario con la respuesta proporcionada por @Alan lo explica todo muy bien. – bor

45

Esto es lo que finalmente funcionó para mí:

<xsd:element name="bar"> 
    <xsd:complexType> 
    <xsd:sequence> 
     <!-- Permit any of these tags in any order in any number  --> 
     <xsd:choice minOccurs="0" maxOccurs="unbounded"> 
     <xsd:element name="child1" type="xsd:string" /> 
     <xsd:element name="child2" type="xsd:string" /> 
     <xsd:element name="child3" type="xsd:string" /> 
     </xsd:choice> 
    </xsd:sequence> 
    </xsd:complexType> 
</xsd:element> 
+5

De hecho, el truco es usar xsd: elección con los cuantificadores tivo

+6

Creo que es importante señalar que el ejemplo anterior funciona incluso sin la secuencia de elementos que encierra la elección- elemento. –

87

La formulación alternativa de la cuestión añadido en una edición posterior parece ser todavía sin respuesta: ¿cómo especificar que entre los hijos de un elemento, tiene que haber uno llamado child3, uno llamado child4, y cualquier número llamado child1 o child2, sin restricción en el orden en que aparecen los niños.

Este es un lenguaje regular definible directamente, y el modelo de contenido que necesita es isomorfo a una expresión regular que define el conjunto de cadenas en el que los dígitos '3' y '4' ocurren exactamente una vez, y los dígitos '1 'y' 2 'ocurren varias veces. Si no es obvio cómo escribir esto, puede ser útil pensar en qué tipo de máquina de estados finitos construirá para reconocer dicho lenguaje. Sería tener al menos cuatro estados distintos:

  • un estado inicial en el que ni '3' ni '4' se ha visto
  • un estado intermedio en el que '3' se ha visto, pero no '4'
  • un estado intermedio en el que '4' se ha visto, pero no '3'
  • un estado final en el que tanto '3' y '4' se han visto

Independientemente del estado en el autómata está en, '1' y '2' pueden leerse; ellos no cambian el estado de la máquina. En el estado inicial, también se aceptarán '3' o '4'; en los estados intermedios, solo se acepta "4" o "3"; en el estado final, ni '3' ni '4' son aceptados. La estructura de la expresión regular es más fácil de entender si en primer lugar definir una expresión regular para el subconjunto de nuestro idioma en el que sólo '3' y '4' se producen:

(34)|(43) 

Para permitir '1' o '2' Para que se produzca cualquier número de veces en una ubicación determinada, podemos insertar (1|2)* (o [12]* si nuestro lenguaje regex acepta esa notación). La inserción de esta expresión en todos los lugares disponibles, obtenemos

(1|2)*((3(1|2)*4)|(4(1|2)*3))(1|2)* 

Traduciendo esto en un modelo de contenido es sencillo. La estructura básica es equivalente a la expresión regular (34)|(43):

<xsd:complexType name="paul0"> 
    <xsd:choice> 
    <xsd:sequence> 
     <xsd:element ref="child3"/> 
     <xsd:element ref="child4"/> 
    </xsd:sequence> 
    <xsd:sequence> 
     <xsd:element ref="child4"/> 
     <xsd:element ref="child3"/> 
    </xsd:sequence> 
    </xsd:choice> 
</xsd:complexType> 

Inserción de un cero o más opciones de child1 y child2 es sencillo:

<xsd:complexType name="paul1"> 
    <xsd:sequence> 
    <xsd:choice minOccurs="0" maxOccurs="unbounded"> 
     <xsd:element ref="child1"/> 
     <xsd:element ref="child2"/> 
    </xsd:choice>  
    <xsd:choice> 
     <xsd:sequence> 
     <xsd:element ref="child3"/> 
     <xsd:choice minOccurs="0" maxOccurs="unbounded"> 
      <xsd:element ref="child1"/> 
      <xsd:element ref="child2"/> 
     </xsd:choice>  
     <xsd:element ref="child4"/> 
     </xsd:sequence> 
     <xsd:sequence> 
     <xsd:element ref="child4"/> 
     <xsd:choice minOccurs="0" maxOccurs="unbounded"> 
      <xsd:element ref="child1"/> 
      <xsd:element ref="child2"/> 
     </xsd:choice>  
     <xsd:element ref="child3"/> 
     </xsd:sequence> 
    </xsd:choice> 
    <xsd:choice minOccurs="0" maxOccurs="unbounded"> 
     <xsd:element ref="child1"/> 
     <xsd:element ref="child2"/> 
    </xsd:choice>  
    </xsd:sequence> 
</xsd:complexType> 

Si queremos minimizar el volumen un poco, puede definir un grupo llamado así por las opciones de repetición de child1 y child2:

<xsd:group name="onetwo"> 
    <xsd:choice> 
    <xsd:element ref="child1"/> 
    <xsd:element ref="child2"/> 
    </xsd:choice> 
</xsd:group> 

<xsd:complexType name="paul2"> 
    <xsd:sequence> 
    <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/> 
    <xsd:choice> 
     <xsd:sequence> 
     <xsd:element ref="child3"/> 
     <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/> 
     <xsd:element ref="child4"/> 
     </xsd:sequence> 
     <xsd:sequence> 
     <xsd:element ref="child4"/> 
     <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/> 
     <xsd:element ref="child3"/> 
     </xsd:sequence> 
    </xsd:choice> 
    <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/> 
    </xsd:sequence> 
</xsd:complexType> 

En XSD 1.1, algunas de las limitaciones de all -grupos se han levantado, por lo que es posible definir este modelo de contenido de manera más concisa:

<xsd:complexType name="paul3"> 
    <xsd:all> 
    <xsd:element ref="child1" minOccurs="0" maxOccurs="unbounded"/> 
    <xsd:element ref="child2" minOccurs="0" maxOccurs="unbounded"/> 
    <xsd:element ref="child3"/> 
    <xsd:element ref="child4"/>  
    </xsd:all> 
</xsd:complexType> 

Pero como se puede ver en los ejemplos dados anteriormente, estos cambios a all -grupos hacer de hecho, no cambian el poder expresivo del lenguaje; solo hacen más sucinta la definición de ciertos tipos de idiomas.

+1

Me gusta el XSD 1.0 xs: toda alternativa. – TWiStErRob

+8

+1. Esta es una respuesta excelente y merece mucho más votos ascendentes. –

+1

¡Gran respuesta! Realmente me gustan las explicaciones como esta. Revela toda la lógica y el razonamiento detrás del logro de la meta. Ahora no solo sé cómo resolver este problema, sino que aprendí un nuevo enfoque para resolver problemas similares. Explicar esto usando una automatización de estado finita es una muy buena idea. – egelev

1

Si nada de lo anterior funciona, probablemente esté trabajando en la trama EDI, donde debe validar su resultado con un esquema HIPPA o cualquier otro xsd complejo para ese asunto. El requisito es que, digamos que hay 8 segmentos REF y cualquiera de ellos debe aparecer en cualquier orden y tampoco todos son obligatorios, significa decir que puede tenerlos en el siguiente orden: 1ª REF, 3ª REF, 2ª REF, 9ª REF. Bajo predeterminado situación EDI recibir fallará, pd tipo complejo por defecto es

<xs:sequence> 
    <xs:element.../> 
</xs:sequence> 

La situación es aún compleja cuando se está llamando a su elemento por refrence y luego el elemento en su lugar original es bastante complejo en sí. por ejemplo:

<xs:element> 
<xs:complexType> 
<xs:sequence> 
<element name="REF1" ref= "REF1_Mycustomelment" minOccurs="0" maxOccurs="1"> 
<element name="REF2" ref= "REF2_Mycustomelment" minOccurs="0" maxOccurs="1"> 
<element name="REF3" ref= "REF3_Mycustomelment" minOccurs="0" maxOccurs="1"> 
</xs:sequence> 
</xs:complexType> 
</xs:element> 

Solución:

Aquí simple sustitución de "secuencia" con "todos" o el uso de "elección" con mín/máx combinaciones no va a funcionar!

Lo primero que reemplace "xs:sequence" with "<xs:all>" Ahora, es necesario hacer algunos cambios en el que se está refiriendo el elemento de, No vaya a:

<xs:annotation> 
    <xs:appinfo> 
    <b:recordinfo structure="delimited" field.........Biztalk/2003"> 

*** Ahora en el segmento anterior añadir punto de disparo en el end like this trigger_field = "REF01 _... nombre completo ..." trigger_value = "38" Haz lo mismo para otros segmentos REF donde el valor de activación será diferente, como por ejemplo "18", "XX", "YY", etc. para que su información de registro ahora se vea así: b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


Esto hará que cada elemento sea único, por lo que todos los segements REF (ejemplo anterior) tienen la misma estructura como REF01, REF02, REF03. Y durante la validación, la validación de la estructura está bien, pero no permite que los valores se repitan porque trata de buscar los valores restantes en la primera REF. Agregar disparadores los hará únicos y pasarán en cualquier orden y casos situacionales (como usar 5 de 9 y no todos 9/9).

Espero que te ayude, ya que he pasado casi 20 horas en esto.

buena suerte

Cuestiones relacionadas