XSD - wie kann man Elemente in beliebiger Reihenfolge beliebig oft zulassen?

109

Ich versuche, eine XSD zu erstellen und die Definition mit der folgenden Anforderung zu schreiben:

  • Zulassen, dass das angegebene untergeordnete Element beliebig oft angezeigt wird (0 bis unbegrenzt)
  • Lassen Sie untergeordnete Elemente in beliebiger Reihenfolge zu

Ich sah mich um und fand verschiedene Lösungen wie diese :

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

Aber soweit ich xs verstehe: Auswahl erlaubt immer noch nur die Auswahl einzelner Elemente. Wenn Sie MaxOccurs so unbegrenzt einstellen, sollte dies nur bedeuten, dass "eines" der untergeordneten Elemente mehrmals angezeigt werden kann. Ist das richtig?

Wenn die obige Lösung falsch ist, wie kann ich das erreichen, was ich oben in meiner Anforderung angegeben habe?

EDIT : Was ist, wenn die Anforderung wie folgt ist?

  • Element child1 child2 kann beliebig oft erscheinen (0 bis unbegrenzt)
  • Elemente in beliebiger Reihenfolge
  • Die Elemente child3 und child4 sollten genau einmal erscheinen.

Zum Beispiel ist diese XML gültig:

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

aber das ist nicht (fehlendes Kind3)

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

Antworten:

61

In dem Schema, das Sie in Ihrer Frage haben child1oder child2das in beliebiger Reihenfolge und beliebig oft angezeigt werden kann. Das klingt also nach dem, wonach Sie suchen.

Bearbeiten: Wenn Sie möchten, dass nur einer von ihnen unbegrenzt oft angezeigt wird, muss der Unbegrenzte stattdessen die Elemente bearbeiten:

Bearbeiten: Feste Eingabe in XML.

Bearbeiten: Großgeschriebenes O 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>
xcut
quelle
Grundsätzlich ja, ich suche nach Elementen child1, child2, die in beliebiger Reihenfolge und beliebig oft erscheinen. Die Antwort, die Sie hier gegeben haben, funktioniert nur für einzelne Elemente, oder? oder löst dies auch meine anforderung?
Jvtech
Das Schema in Ihrer Frage entspricht Ihren Anforderungen. Das alternative Schema in meiner Antwort bezieht sich auf ein einzelnes Element. Hoffe das klärt es auf! :)
xcut
@Pavel, @xcut, Danke für die Klarstellung, siehe bearbeitete Anforderung .. irgendwelche Gedanken?
Jvtech
2
jvtech: Sie können diese bearbeitete Anforderung nicht mit einem XML-Schema erfüllen. Der einzige Weg, dies zu erreichen, wäre, wenn child3 und child4 nur am Ende erscheinen können. In diesem Fall benötigen Sie eine Sequenz, die eine Auswahl und dann die beiden Elemente enthält.
xcut
1
@ Daij-Djan Ich fand auch, dass es nicht funktioniert hat. Versuchen Sie, maxOccurs = "unbegrenzt" zum Auswahlelement hinzuzufügen, damit mehr als ein untergeordnetes Element zulässig ist.
MikeD
107

Die alternative Formulierung der Frage, die in einer späteren Bearbeitung hinzugefügt wurde, scheint immer noch unbeantwortet zu sein: Wie kann man angeben, dass unter den untergeordneten Elementen eines Elements ein Name child3, ein Name child4und eine beliebige Nummer child1oder child2ohne Einschränkung der Reihenfolge in vorhanden sein muss ? welche die Kinder erscheinen.

Dies ist eine einfach zu definierende reguläre Sprache, und das von Ihnen benötigte Inhaltsmodell ist isomorph zu einem regulären Ausdruck, der die Menge der Zeichenfolgen definiert, in denen die Ziffern '3' und '4' jeweils genau einmal vorkommen, sowie die Ziffern '1' und '2' 'beliebig oft auftreten. Wenn es nicht offensichtlich ist, wie man das schreibt, kann es hilfreich sein, darüber nachzudenken, welche Art von endlicher Zustandsmaschine Sie bauen würden, um eine solche Sprache zu erkennen. Es hätte mindestens vier verschiedene Zustände:

  • ein Ausgangszustand, in dem weder '3' noch '4' gesehen wurden
  • ein Zwischenzustand, in dem '3' gesehen wurde, aber nicht '4'
  • ein Zwischenzustand, in dem '4' gesehen wurde, aber nicht '3'
  • ein Endzustand, in dem sowohl '3' als auch '4' gesehen wurden

Unabhängig davon, in welchem ​​Zustand sich der Automat befindet, können '1' und '2' gelesen werden. Sie ändern den Zustand der Maschine nicht. Im Ausgangszustand wird auch '3' oder '4' akzeptiert; in den Zwischenzuständen wird nur '4' oder '3' akzeptiert; im Endzustand wird weder '3' noch '4' akzeptiert. Die Struktur des regulären Ausdrucks ist am einfachsten zu verstehen, wenn wir zuerst einen regulären Ausdruck für die Teilmenge unserer Sprache definieren, in der nur '3' und '4' vorkommen:

(34)|(43)

Damit '1' oder '2' an einem bestimmten Ort beliebig oft vorkommen kann, können wir einfügen (1|2)*(oder [12]*wenn unsere Regex-Sprache diese Notation akzeptiert). Wenn wir diesen Ausdruck an allen verfügbaren Stellen einfügen, erhalten wir

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

Die Übersetzung in ein Inhaltsmodell ist unkompliziert. Die Grundstruktur entspricht dem regulären Ausdruck (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>

Das Einfügen einer Auswahl von null oder mehr von child1und child2ist unkompliziert:

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

Wenn wir die Masse ein wenig minimieren möchten, können wir eine benannte Gruppe für die sich wiederholenden Auswahlmöglichkeiten von child1und definieren 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 wurden einige Einschränkungen für allGruppen aufgehoben, sodass dieses Inhaltsmodell präziser definiert werden kann:

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

Aber wie aus den zuvor gegebenen Beispielen ersichtlich ist all, ändern diese Änderungen an -Gruppen tatsächlich nicht die Ausdruckskraft der Sprache; Sie machen nur die Definition bestimmter Arten von Sprachen prägnanter.

CM Sperberg-McQueen
quelle
3
Ich mag die XSD 1.0 xs: alle alternativ.
TWiStErRob
8
+1. Dies ist eine ausgezeichnete Antwort und verdient viel mehr Stimmen.
Christoffer Lette
1
Gute Antwort ! Ich mag solche Erklärungen sehr. Es enthüllt die gesamte Logik und die Gründe für die Erreichung des Ziels. Jetzt weiß ich nicht nur, wie man dieses Problem löst, sondern habe auch einen neuen Ansatz zur Lösung ähnlicher Probleme gelernt. Dies mit einer endlichen Zustandsautomatisierung zu erklären, ist eine sehr gute Idee.
Egelev
3
Michael, du sagst "diese Änderungen an allen Gruppen ändern tatsächlich nicht die Ausdruckskraft der Sprache; sie machen nur die Definition bestimmter Arten von Sprachen prägnanter". Wenn Sie das Problem jedoch auf eine beliebige Anzahl von untergeordneten Elementen verallgemeinern, von denen eine Teilmenge einmal und eine andere Teilmenge beliebig oft auftreten kann, würde die XSD 1.0-Lösung einer kombinatorischen Explosion nachgeben, nicht wahr? Während die XSD 1.1-Lösung sauber bleiben würde.
Ebruchez
1
ebruchez, ja - Ausdruckskraft , wie ich den Begriff benutze, ist nicht dasselbe wie Prägnanz , Kompaktheit , Knappheit oder Handhabbarkeit . Die Ausdruckskraft fragt nur: "Kann dieser Formalismus diese Sprache definieren?" Es wird nicht nach der Größe der Grammatik gefragt oder danach, ob etwas syntaktischer Zucker sie kleiner machen würde. Die von Ihnen erwähnte kombinatorische Explosion bedeutet, dass die Handhabung großer Mengen von Elementen ohne die XSD 1.1-Änderungen an allen Gruppen sehr schnell sehr unangenehm wird (und bei großen n kann der Speicher erschöpft sein). Dies bedeutet nicht, dass sie im Prinzip unmöglich werden.
CM Sperberg-McQueen
49

Das hat endlich bei mir funktioniert:

<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>
Alan
quelle
5
In der Tat besteht der Trick darin, xsd: choice mit den Quantifizierern zu verwenden <xsd: choice minOccurs = "0" maxOccurs = "unbounded">
tivo
6
Ich denke, es ist erwähnenswert, dass das obige Beispiel auch ohne das Sequenzelement funktioniert, das das Auswahlelement einschließt.
9

Aber soweit ich xs verstehe: Auswahl erlaubt immer noch nur die Auswahl einzelner Elemente. Wenn Sie MaxOccurs so unbegrenzt einstellen, sollte dies nur bedeuten, dass "eines" der untergeordneten Elemente mehrmals angezeigt werden kann. Ist das richtig?

Nein. Die Auswahl erfolgt individuell für jede "Wiederholung" xs:choice, die aufgrund von erfolgt maxOccurs="unbounded". Daher ist der von Ihnen gepostete Code korrekt und macht tatsächlich das, was Sie wollen, wie geschrieben.

Pavel Minaev
quelle
Ihr Kommentar mit der Antwort von @Alan erklärt alles gut.
Bor
3

Sie sollten feststellen, dass das folgende Schema das zulässt, was Sie vorgeschlagen haben.

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

Auf diese Weise können Sie eine Datei erstellen, z.

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

Welches scheint Ihrer Frage zu entsprechen.

Steven_W
quelle
minOccursund maxOccurssind auf 1 für Kinder von beschränkt xs:all.
Pavel Minaev
Pavel: Danke ... Ich habe das herausgefunden, nachdem ich meinen Beitrag überprüft und dann bearbeitet habe, um die xs: all zu entfernen
Steven_W
1

Wenn keines der oben genannten Verfahren funktioniert, arbeiten Sie wahrscheinlich an der EDI-Transaktion, bei der Sie Ihr Ergebnis anhand eines HIPPA-Schemas oder einer anderen komplexen xsd-Datei validieren müssen. Die Anforderung ist, dass beispielsweise 8 REF-Segmente vorhanden sind und eines von ihnen in beliebiger Reihenfolge erscheinen muss und auch nicht alle erforderlich sind. Dies bedeutet, dass Sie sie möglicherweise in der folgenden Reihenfolge haben: 1. REF, 3. REF, 2. REF, 9. REF. In der Standardsituation schlägt der EDI-Empfang fehl, da der Standardkomplextyp lautet

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

Die Situation ist sogar komplex, wenn Sie Ihr Element durch Auffrischung aufrufen und dann das Element an seiner ursprünglichen Stelle selbst ziemlich komplex ist. beispielsweise:

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

Lösung:

Hier funktioniert es nicht, einfach "Sequenz" durch "Alle" zu ersetzen oder "Auswahl" durch Min / Max-Kombinationen zu verwenden!

Als erstes ersetzen "xs:sequence" with "<xs:all>" Jetzt müssen Sie einige Änderungen vornehmen, von denen aus Sie auf das Element verweisen. Gehen Sie zu:

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

*** Fügen Sie nun im obigen Segment am Ende den Triggerpunkt wie folgt hinzu: trigger_field = "REF01 _... vollständiger Name .." trigger_value = "38" Machen Sie dasselbe für andere REF-Segmente, bei denen der Triggerwert unterschiedlich ist, wie z. B. "18" "," XX "," YY "usw., damit Ihre Datensatzinformationen jetzt wie folgt aussehen:b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


Dies macht jedes Element einzigartig, da alle REF-Segmente (obiges Beispiel) dieselbe Struktur wie REF01, REF02, REF03 haben. Während der Validierung ist die Strukturvalidierung in Ordnung, lässt die Werte jedoch nicht wiederholen, da versucht wird, im ersten REF selbst nach verbleibenden Werten zu suchen. Das Hinzufügen von Triggern macht sie alle einzigartig und sie werden in beliebiger Reihenfolge und in bestimmten Situationen bestanden (wie z. B. 5 von 9 und nicht alle 9/9).

Hoffe es hilft dir, denn ich habe fast 20 Stunden damit verbracht.

Viel Glück

Prabhdeep Gill
quelle