XSD - come consentire elementi in qualsiasi ordine un numero qualsiasi di volte?


109

Sto cercando di creare un XSD e sto cercando di scrivere la definizione con il seguente requisito:

  • Consenti all'elemento figlio specificato di apparire un numero qualsiasi di volte (da 0 a illimitato)
  • Consenti agli elementi figlio di essere in qualsiasi ordine

Mi sono guardato intorno e ho trovato varie soluzioni come questa :

<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>

Ma da quello che ho capito xs: choice consente ancora solo la selezione di un singolo elemento. Quindi l'impostazione di MaxOccurs su illimitato in questo modo dovrebbe significare solo che "uno qualsiasi" degli elementi figlio può apparire più volte. È accurato?

Se la soluzione di cui sopra non è corretta, come posso ottenere ciò che ho dichiarato sopra nella mia richiesta?

EDIT : cosa succede se il requisito è il seguente?

  • L'elemento child1 child2 può apparire un numero qualsiasi di volte (da 0 a illimitato)
  • Gli elementi devono essere in qualsiasi ordine
  • Gli elementi child3 e child4 dovrebbero apparire esattamente una volta.

Ad esempio, questo xml è valido:

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

ma questo non è (bambino scomparso3)

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

Risposte:


61

Nello schema che hai nella tua domanda, child1o child2può apparire in qualsiasi ordine, un numero qualsiasi di volte. Quindi questo suona come quello che stai cercando.

Modifica: se desideri che solo uno di essi appaia un numero illimitato di volte, il illimitato dovrebbe invece andare sugli elementi:

Modifica: tipo fisso in XML.

Modifica: O maiuscola in maxOccurs

<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>

fondamentalmente sì, sto cercando gli elementi child1, child2 per apparire in qualsiasi ordine, un numero qualsiasi di volte .. la risposta che hai fornito qui funziona solo per un singolo elemento, giusto? o questo risolve anche la mia esigenza?
jvtech

Lo schema nella tua domanda soddisfa le tue esigenze; lo schema alternativo nella mia risposta è per un singolo elemento. Spero che questo chiarisca tutto! :)
xcut

@Pavel, @xcut, grazie per il chiarimento, vedi requisito modificato .. qualche idea?
jvtech

2
jvtech: non è possibile soddisfare tale requisito modificato con lo schema XML; l'unico modo per ottenerlo sarebbe se child3 e child4 potessero apparire solo alla fine. In tal caso è necessaria una sequenza contenente una scelta e quindi i due elementi.
xcut

1
@ Daij-Djan ho anche scoperto che non funzionava. Prova ad aggiungere maxOccurs = "unbounded" all'elemento choice in modo che sia consentito più di un elemento figlio.
MikeD

107

La formulazione alternativa della domanda aggiunta in una modifica successiva sembra essere ancora senza risposta: come specificare che tra i figli di un elemento deve essercene uno con nome child3, uno con nome child4e un numero qualsiasi child1o child2, senza vincoli sull'ordine in che appaiono i bambini.

Si tratta di un linguaggio regolare definibile in modo semplice e il modello di contenuto necessario è isomorfo a un'espressione regolare che definisce l'insieme di stringhe in cui le cifre "3" e "4" ricorrono ciascuna esattamente una volta e le cifre "1" e "2" 'si verificano un numero qualsiasi di volte. Se non è ovvio come scriverlo, può essere utile pensare a quale tipo di macchina a stati finiti costruiresti per riconoscere tale linguaggio. Avrebbe almeno quattro stati distinti:

  • uno stato iniziale in cui non è stato visto né "3" né "4"
  • uno stato intermedio in cui è stato visto "3" ma non "4"
  • uno stato intermedio in cui è stato visto "4" ma non "3"
  • uno stato finale in cui sono stati visti sia "3" che "4"

Indipendentemente dallo stato in cui si trova l'automa, è possibile leggere "1" e "2"; non modificano lo stato della macchina. Nello stato iniziale verranno accettati anche "3" o "4"; negli stati intermedi si accetta solo "4" o "3"; nello stato finale, né "3" né "4" sono accettati. La struttura dell'espressione regolare è più facile da capire se definiamo prima una regex per il sottoinsieme della nostra lingua in cui si verificano solo "3" e "4":

(34)|(43)

Per consentire a "1" o "2" di verificarsi un numero qualsiasi di volte in una determinata posizione, possiamo inserire (1|2)*(o [12]*se il nostro linguaggio regex accetta quella notazione). Inserendo questa espressione in tutte le posizioni disponibili, otteniamo

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

Tradurre questo in un modello di contenuto è semplice. La struttura di base è equivalente alla regex (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>

L'inserimento di una scelta zero o più di child1ed child2è semplice:

<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>

Se vogliamo minimizzare un po 'il volume, possiamo definire un gruppo denominato per le scelte ripetute di child1e 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>

In XSD 1.1, alcuni dei vincoli sui allgruppi sono stati rimossi, quindi è possibile definire questo modello di contenuto in modo più conciso:

<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>

Ma come si può vedere dagli esempi forniti in precedenza, queste modifiche a all-gruppi di fatto non cambiano la forza espressiva del linguaggio; rendono solo più succinta la definizione di certi tipi di lingue.


3
Mi piace XSD 1.0 xs: tutte alternative.
TWiStErRob

8
+1. Questa è un'ottima risposta e merita molti più voti positivi.
Christoffer Lette

1
Bella risposta ! Mi piacciono molto le spiegazioni come questa. Rivela tutta la logica e il ragionamento alla base del raggiungimento dell'obiettivo. Ora non solo so come risolvere questo problema, ma ho imparato un nuovo approccio per risolvere problemi simili. Spiegarlo usando un'automazione a stati finiti è un'ottima idea.
egelev

3
Michael, tu dici "questi cambiamenti a tutti i gruppi in realtà non cambiano il potere espressivo del linguaggio; rendono solo più succinta la definizione di certi tipi di lingue". Ma se generalizzi il problema a un numero qualsiasi di elementi figli, un sottoinsieme dei quali può apparire una volta e un altro sottoinsieme che può apparire un numero qualsiasi di volte, la soluzione XSD 1.0 produrrebbe un'esplosione combinatoria, non è vero? Mentre la soluzione XSD 1.1 rimarrebbe pulita.
ebruchez

1
ebruchez, sì - la forza espressiva , come uso il termine, non è la stessa cosa di sinteticità , compattezza , lacune o gestibilità . Il potere espressivo chiede solo: "Può questo formalismo definire questo linguaggio?" Non chiede la dimensione della grammatica o se un po 'di zucchero sintattico la renderebbe più piccola. L'esplosione combinatoria di cui parli significa che la gestione di grandi insiemi di elementi senza le modifiche XSD 1.1 a tutti i gruppi diventa molto sgradevole molto velocemente (e per grandi n può esaurire la memoria). Ciò non significa che diventino impossibili in linea di principio.
CM Sperberg-McQueen

49

Questo è ciò che alla fine ha funzionato per me:

<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
In effetti il ​​trucco sta nell'usare xsd: choice con i quantificatori <xsd: choice minOccurs = "0" maxOccurs = "unbounded">
tivo

6
Penso che valga la pena sottolineare che l'esempio sopra funziona anche senza l'elemento sequenza che racchiude l'elemento scelta.

9

Ma da quello che ho capito xs: choice consente ancora solo la selezione di un singolo elemento. Quindi l'impostazione di MaxOccurs su illimitato in questo modo dovrebbe significare solo che "uno qualsiasi" degli elementi figlio può apparire più volte. È accurato?

No. La scelta avviene individualmente per ogni "ripetizione" di xs:choiceciò che avviene a causa di maxOccurs="unbounded". Pertanto, il codice che hai pubblicato è corretto e farà effettivamente quello che vuoi come scritto.


Il tuo commento con la risposta fornita da @Alan spiega tutto bene.
Bor

3

Dovresti scoprire che il seguente schema consente ciò che hai proposto.

  <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>

Ciò ti consentirà di creare un file come:

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

Che sembra corrispondere alla tua domanda.


minOccurse maxOccurssono limitati a 1 per i bambini di xs:all.
Pavel Minaev

Pavel: Grazie ... L'ho scoperto dopo aver ricontrollato il mio post e poi modificato per rimuovere xs: all
Steven_W

1

Se nessuna delle opzioni precedenti funziona, probabilmente stai lavorando alla trasazione EDI in cui devi convalidare il tuo risultato rispetto a uno schema HIPPA o qualsiasi altro xsd complesso per quella materia. Il requisito è che, diciamo che ci siano 8 segmenti REF e ognuno di essi deve apparire in qualsiasi ordine e inoltre non tutti sono obbligatori, significa che puoi averli nel seguente ordine 1 ° RIF, 3 ° RIF, 2 ° RIF, 9 ° RIF. In una situazione predefinita, la ricezione EDI fallirà, perché il tipo complesso predefinito è

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

La situazione è persino complessa quando chiami il tuo elemento per rifrazione e quindi quell'elemento nel suo posto originale è abbastanza complesso di per sé. per esempio:

<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>

Soluzione:

Qui semplicemente sostituire "sequenza" con "tutto" o usare "scelta" con combinazioni min / max non funzionerà!

Per prima cosa sostituisci "xs:sequence" with "<xs:all>" Ora, devi apportare alcune modifiche al punto da cui stai facendo riferimento all'elemento, vai a:

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

*** Ora nel segmento sopra aggiungi il punto trigger alla fine in questo modo trigger_field = "REF01 _... nome completo .." trigger_value = "38" Fai lo stesso per gli altri segmenti REF dove il valore del trigger sarà diverso come ad esempio "18 "," XX "," YY "ecc. In modo che le informazioni del tuo record ora abbiano il seguente aspetto:b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


Questo renderà ogni elemento unico, perché tutti i segmenti REF (esempio sopra) hanno la stessa struttura come REF01, REF02, REF03. E durante la convalida la convalida della struttura è ok ma non lascia che i valori si ripetano perché cerca di cercare i valori rimanenti nel primo REF stesso. L'aggiunta di trigger li renderà tutti unici e passeranno in qualsiasi ordine e caso situazionale (come utilizzare 5 su 9 e non tutti 9/9).

Spero che ti aiuti, perché ho impiegato quasi 20 ore su questo.

In bocca al lupo

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.