XSD - bagaimana cara mengizinkan elemen dalam urutan berapa pun berapa kali?


109

Saya mencoba membuat XSD, dan mencoba menulis definisi dengan persyaratan berikut:

  • Izinkan elemen turunan yang ditentukan untuk muncul berapa kali (0 hingga tidak terbatas)
  • Izinkan elemen anak berada dalam urutan apa pun

Saya melihat sekeliling dan menemukan berbagai solusi seperti ini :

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

Tapi dari apa yang saya pahami xs: pilihan masih hanya memungkinkan pemilihan elemen tunggal. Oleh karena itu, menyetel MaxOccurs menjadi tidak terbatas seperti ini hanya berarti bahwa "salah satu" dari elemen anak dapat muncul beberapa kali. Apakah ini akurat?

Jika solusi di atas tidak benar, bagaimana saya bisa mencapai apa yang saya sebutkan di atas dalam kebutuhan saya?

EDIT : Bagaimana jika persyaratannya adalah sebagai berikut?

  • Elemen child1 child2 dapat muncul berapa kali (0 hingga tidak terbatas)
  • Elemen harus dalam urutan apa pun
  • Elemen child3 dan child4 harus muncul tepat satu kali.

Misalnya, xml ini valid:

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

tapi ini bukan (anak hilang3)

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

Jawaban:


61

Dalam skema yang Anda miliki dalam pertanyaan Anda, child1atau child2dapat muncul dalam urutan apa pun, berapa kali. Jadi ini terdengar seperti yang Anda cari.

Sunting: jika Anda ingin hanya satu dari mereka yang muncul dalam jumlah yang tidak terbatas, yang tidak dibatasi harus menggunakan elemen sebagai gantinya:

Edit: Jenis tetap dalam XML.

Edit: Huruf besar O dalam 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>

pada dasarnya ya, saya mencari elemen child1, child2 untuk muncul dalam urutan apa pun, berapa kali .. jawaban yang Anda berikan di sini hanya berfungsi untuk elemen tunggal, bukan? atau apakah ini juga menyelesaikan kebutuhan saya?
jvtech

Skema dalam pertanyaan Anda memenuhi kebutuhan Anda; skema alternatif dalam jawaban saya adalah untuk satu elemen. Harapan yang menyelesaikannya! :)
xcut

@Pavel, @xcut, Terima kasih atas klarifikasinya, lihat persyaratan yang diedit .. ada pendapat?
jvtech

2
jvtech: Anda tidak dapat memenuhi persyaratan yang diedit tersebut dengan skema XML; satu-satunya cara untuk mencapainya adalah jika child3 dan child4 hanya dapat muncul di bagian akhir. Dalam hal ini Anda memerlukan urutan yang berisi pilihan dan kemudian dua elemen.
xcut

1
@ Daij-Djan Saya juga menemukan bahwa itu tidak berhasil. Coba tambahkan maxOccurs = "unbounded" pada elemen pilihan sehingga lebih dari satu elemen turunan diizinkan.
MikeD

107

Formulasi alternatif dari pertanyaan yang ditambahkan dalam pengeditan selanjutnya tampaknya masih belum terjawab: bagaimana menentukan bahwa di antara anak-anak elemen, harus ada satu yang dinamai child3, satu nama child4, dan nomor apa pun yang dinamai child1atau child2, tanpa batasan pada urutan di dimana anak-anak muncul.

Ini adalah bahasa reguler yang dapat didefinisikan langsung, dan model konten yang Anda butuhkan adalah isomorfik ke ekspresi reguler yang mendefinisikan kumpulan string di mana angka '3' dan '4' masing-masing muncul tepat satu kali, dan angka '1' dan '2 'terjadi beberapa kali. Jika tidak jelas bagaimana menulis ini, mungkin membantu untuk memikirkan jenis mesin keadaan terbatas apa yang akan Anda bangun untuk mengenali bahasa seperti itu. Ini akan memiliki setidaknya empat keadaan berbeda:

  • keadaan awal di mana baik '3' maupun '4' tidak terlihat
  • keadaan perantara di mana '3' telah terlihat tetapi tidak '4'
  • keadaan perantara di mana '4' telah terlihat tetapi bukan '3'
  • keadaan terakhir di mana '3' dan '4' telah terlihat

Tidak peduli di negara bagian apa robot itu berada, '1' dan '2' dapat dibaca; mereka tidak mengubah status mesin. Dalam keadaan awal, '3' atau '4' juga akan diterima; di negara bagian menengah, hanya '4' atau '3' yang diterima; dalam keadaan akhir, baik '3' maupun '4' tidak diterima. Struktur ekspresi reguler paling mudah dipahami jika kita pertama kali mendefinisikan regex untuk subset bahasa kita di mana hanya '3' dan '4' yang muncul:

(34)|(43)

Untuk mengizinkan '1' atau '2' muncul beberapa kali di lokasi tertentu, kita dapat menyisipkan (1|2)*(atau [12]*jika bahasa regex kita menerima notasi itu). Memasukkan ekspresi ini di semua lokasi yang tersedia, kita dapatkan

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

Menerjemahkan ini ke dalam model konten sangatlah mudah. Struktur dasarnya setara dengan 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>

Memasukkan pilihan nol-atau-lebih child1dan child2langsung:

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

Jika kita ingin meminimalkan sebagian besar, kita dapat menentukan grup bernama untuk pilihan berulang child1dan 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>

Di XSD 1.1, beberapa batasan pada all-groups telah dicabut, jadi mungkin saja untuk mendefinisikan model konten ini secara lebih ringkas:

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

Tapi seperti yang bisa dilihat dari contoh yang diberikan sebelumnya, perubahan pada all-group ini sebenarnya tidak mengubah kekuatan ekspresif bahasa; mereka hanya membuat definisi jenis bahasa tertentu lebih ringkas.


3
Saya suka XSD 1.0 xs: semua alternatif.
TWiStErRob

8
+1. Ini adalah jawaban yang sangat bagus dan layak mendapat lebih banyak suara positif.
Christoffer Lette

1
Jawaban yang bagus! Saya sangat suka penjelasan seperti ini. Ini mengungkapkan semua logika dan alasan di balik pencapaian tujuan. Sekarang saya tidak hanya tahu bagaimana memecahkan masalah ini, tetapi saya belajar pendekatan baru untuk memecahkan masalah serupa. Menjelaskan hal ini menggunakan otomatisasi keadaan terbatas adalah ide yang sangat bagus.
egelev

3
Michael, Anda mengatakan "perubahan pada semua kelompok ini sebenarnya tidak mengubah kekuatan ekspresif bahasa; mereka hanya membuat definisi jenis bahasa tertentu lebih ringkas". Tetapi jika Anda menggeneralisasi masalah ke sejumlah elemen turunan, subset yang dapat muncul satu kali dan subset lain yang dapat muncul beberapa kali, solusi XSD 1.0 akan menghasilkan ledakan kombinatorial, bukan? Sedangkan solusi XSD 1.1 akan tetap bersih.
ebruchez

1
ebruchez, ya - kekuatan ekspresif , karena saya menggunakan istilah, adalah tidak sama dengan kekompakan , kekompakan , terseness , atau pengelolaan . Kekuatan ekspresif hanya bertanya "Bisakah formalisme ini mendefinisikan bahasa ini?" Itu tidak menanyakan tentang ukuran tata bahasa, atau tentang apakah beberapa gula sintaksis akan membuatnya lebih kecil. Ledakan kombinatorial yang Anda sebutkan berarti bahwa menangani kumpulan besar elemen tanpa perubahan XSD 1.1 ke semua grup menjadi sangat tidak menyenangkan dengan sangat cepat (dan untuk n yang besar dapat menghabiskan memori). Ini tidak berarti bahwa pada prinsipnya mereka menjadi tidak mungkin.
CM Sperberg-McQueen

49

Inilah yang akhirnya berhasil untuk saya:

<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
Memang triknya adalah menggunakan xsd: choice dengan pembilang <xsd: choice minOccurs = "0" maxOccurs = "unbounded">
tivo

6
Saya pikir ada baiknya menunjukkan bahwa contoh di atas berfungsi bahkan tanpa urutan-elemen yang melampirkan pilihan-elemen.

9

Tapi dari apa yang saya pahami xs: pilihan masih hanya memungkinkan pemilihan elemen tunggal. Oleh karena itu, menyetel MaxOccurs menjadi tidak terbatas seperti ini hanya berarti bahwa "salah satu" dari elemen anak dapat muncul beberapa kali. Apakah ini akurat?

Tidak. Pilihan terjadi secara individual untuk setiap "pengulangan" xs:choiceyang terjadi karena maxOccurs="unbounded". Oleh karena itu, kode yang Anda posting sudah benar, dan benar-benar akan melakukan apa yang Anda inginkan seperti yang tertulis.


Komentar Anda dengan jawaban yang diberikan oleh @Alan menjelaskan semuanya dengan baik.
bor

3

Anda harus menemukan bahwa skema berikut memungkinkan apa yang Anda usulkan.

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

Ini akan memungkinkan Anda untuk membuat file seperti:

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

Yang sepertinya cocok dengan pertanyaan Anda.


minOccursdan maxOccursdibatasi 1 untuk anak-anak xs:all.
Pavel Minaev

Pavel: Terima kasih ... Saya menemukan ini setelah memeriksa ulang posting saya dan kemudian mengeditnya untuk menghapus xs: all
Steven_W

1

Jika semua hal di atas tidak berfungsi, Anda mungkin sedang mengerjakan traksi EDI di mana Anda perlu memvalidasi hasil Anda terhadap skema HIPPA atau xsd kompleks lainnya dalam hal ini. Syaratnya, misalkan ada 8 segmen REF dan salah satunya harus muncul dalam urutan apapun dan juga tidak semuanya wajib, artinya anda boleh memilikinya dalam urutan mengikuti REF 1, REF 3, REF 2, REF 9. Dalam situasi default yang menerima EDI akan gagal, karena tipe kompleks default adalah

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

Situasinya bahkan menjadi rumit ketika Anda memanggil elemen Anda dengan refence dan kemudian elemen itu di tempat aslinya cukup kompleks. sebagai contoh:

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

Larutan:

Di sini hanya mengganti "urutan" dengan "semua" atau menggunakan "pilihan" dengan kombinasi min / maks tidak akan berfungsi!

Hal pertama ganti "xs:sequence" with "<xs:all>" Sekarang, Anda perlu membuat beberapa perubahan di mana Anda merujuk elemen, Pergi ke:

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

*** Sekarang di segmen di atas tambahkan titik pemicu pada akhirnya seperti ini trigger_field = "REF01 _... nama lengkap .." trigger_value = "38" Lakukan hal yang sama untuk segmen REF lainnya di mana nilai pemicu akan berbeda seperti katakan "18 "," XX "," YY "dll .. sehingga info rekaman Anda sekarang terlihat seperti:b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


Ini akan membuat setiap elemen unik, karena Semua segmen REF (contoh di atas) memiliki struktur yang sama seperti REF01, REF02, REF03. Dan selama validasi, validasi struktur baik-baik saja tetapi tidak membiarkan nilai-nilai berulang karena mencoba mencari nilai yang tersisa di REF pertama itu sendiri. Menambahkan pemicu akan membuat semuanya unik dan akan diteruskan dalam urutan dan kasus situasional apa pun (seperti gunakan 5 dari 9 dan tidak semua 9/9).

Semoga ini membantu Anda, karena saya menghabiskan hampir 20 jam untuk ini.

Semoga berhasil

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.