XSD - elemanlara herhangi bir sırayla herhangi bir sayıda nasıl izin verilir?


109

Bir XSD oluşturmaya çalışıyorum ve aşağıdaki gereksinimle tanımı yazmaya çalışıyorum:

  • Belirtilen alt öğenin herhangi bir sayıda görünmesine izin ver (0 - sınırsız)
  • Alt öğelerin herhangi bir sırada olmasına izin ver

Etrafıma baktım ve bunun gibi çeşitli çözümler buldum :

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

Ama anladığım kadarıyla xs: seçim hala sadece tek eleman seçimine izin veriyor. Bu nedenle, MaxOccurs'u bu şekilde sınırsız olarak ayarlamak, yalnızca alt öğelerin "herhangi birinin" birden çok kez görünebileceği anlamına gelmelidir. Bu doğru mu?

Yukarıdaki çözüm yanlışsa, gereksinimimde yukarıda belirttiğim şeyi nasıl başarabilirim?

DÜZENLEME : Gereklilik aşağıdaki gibiyse ne olur?

  • Child1 child2 öğesi herhangi bir sayıda görünebilir (0 - sınırsız)
  • Herhangi bir sırada olması gereken öğeler
  • Child3 ve child4 öğeleri tam olarak bir kez görünmelidir.

Örneğin, bu xml geçerlidir:

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

ama bu değil (child3 eksik)

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

Yanıtlar:


62

Şemada sorunuz var child1veya child2herhangi bir sırada, herhangi bir sayıda görünebilir. Bu, aradığınız şeye benziyor.

Düzenleme: Bunlardan yalnızca birinin sınırsız sayıda görünmesini istiyorsanız, bunun yerine sınırsız olanın öğelere gitmesi gerekir:

Düzen: XML'de sabit yazım.

Düzenleme: MaxOccurs'da Büyük Harfli O

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

temelde evet, herhangi bir sırada, herhangi bir sayıda görünmesi için child1, child2 öğelerini arıyorum .. Burada verdiğiniz yanıt yalnızca tek öğe için çalışıyor, değil mi? yoksa bu benim ihtiyacımı da çözüyor mu?
jvtech

Sorunuzdaki şema gereksinimlerinizi karşılar; cevabımdaki alternatif şema tek bir öğe içindir. Umarim bu acikliga kavusturur! :)
xcut

@Pavel, @xcut, Açıklama için teşekkürler, düzenlenmiş gereksinime bakın .. herhangi bir fikriniz var mı?
jvtech

2
jvtech: XML şemasıyla bu düzenlenmiş gereksinimi karşılayamazsınız; Bunu başarmanın tek yolu, child3 ve child4'ün yalnızca sonunda ortaya çıkabilmesidir. Bu durumda bir seçim ve ardından iki öğe içeren bir diziye ihtiyacınız vardır.
xcut

1
@ Daij-Djan Ben de işe yaramadığını buldum. Birden fazla alt elemana izin verilmesi için seçim elemanına maxOccurs = "sınırsız" eklemeyi deneyin.
MikeD

107

Daha sonraki bir düzenlemede eklenen sorunun alternatif formülasyonu hala cevaplanmamış gibi görünüyor: bir elemanın alt öğeleri arasında bir adlandırılmış child3, bir isimlendirilmiş child4ve herhangi bir numaranın olması gerektiğini belirtmek için child1veya child2, sırayla herhangi bir kısıtlama olmaksızın çocukların göründüğü.

Bu, doğrudan tanımlanabilir bir normal dildir ve ihtiyacınız olan içerik modeli, '3' ve '4' rakamlarının her birinin tam olarak bir kez geçtiği ve '1' ve '2 rakamlarının bulunduğu dizeler kümesini tanımlayan düzenli bir ifadeye izomorfiktir. 'herhangi bir sayıda meydana gelir. Bunu nasıl yazacağınız açık değilse, böyle bir dili tanımak için ne tür bir sonlu durum makinesi inşa edeceğinizi düşünmek yardımcı olabilir. En az dört farklı durumu olacaktır:

  • ne '3' ne de '4' görülmeyen bir başlangıç ​​durumu
  • '3'ün görüldüğü ancak' 4'ün görülmediği bir ara durum
  • '4'ün görüldüğü ancak' 3'ün görülmediği bir ara durum
  • hem '3' hem de '4'ün görüldüğü son durum

Otomat hangi durumda olursa olsun, '1' ve '2' okunabilir; makinenin durumunu değiştirmezler. İlk durumda, '3' veya '4' de kabul edilecektir; ara eyaletlerde yalnızca '4' veya '3' kabul edilir; son durumda, ne '3' ne de '4' kabul edilir. Normal ifadenin yapısını anlamak en kolay olanı, ilk önce dilimizin alt kümesi için yalnızca '3' ve '4'ün geçtiği bir normal ifade tanımlarsak:

(34)|(43)

'1' veya '2'nin belirli bir konumda herhangi bir sayıda geçmesine izin vermek için, ekleyebiliriz (1|2)*(veya [12]*normal ifade dilimiz bu gösterimi kabul ederse). Bu ifadeyi mevcut tüm konumlara ekleyerek,

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

Bunu bir içerik modeline çevirmek basittir. Temel yapı, normal ifadeye eşdeğerdir (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>

Sıfır veya daha fazla seçenek eklemek child1ve child2basittir:

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

Yığını biraz küçültmek istersek, yinelenen child1ve seçenekleri için adlandırılmış bir grup tanımlayabiliriz 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>

XSD 1.1'de, allgruplar üzerindeki bazı kısıtlamalar kaldırılmıştır, bu nedenle bu içerik modelini daha net bir şekilde tanımlamak mümkündür:

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

Ancak daha önce verilen örneklerden görülebileceği gibi, allgruplara yapılan bu değişiklikler aslında dilin ifade gücünü değiştirmez; sadece belirli dil türlerinin tanımını daha kısa ve öz yaparlar.


3
XSD 1.0 xs'i seviyorum: tüm alternatifler.
TWiStErRob

8
+1. Bu mükemmel bir cevap ve çok daha fazla oyu hak ediyor.
Christoffer Lette

1
Mükemmel cevap ! Böyle açıklamaları gerçekten seviyorum. Hedefe ulaşmanın ardındaki tüm mantığı ve mantığı ortaya çıkarır. Şimdi sadece bu sorunu nasıl çözeceğimi bilmiyorum, aynı zamanda benzer sorunları çözmek için yeni bir yaklaşım da öğrendim. Bunu sonlu durum otomasyonu kullanarak açıklamak çok iyi bir fikirdir.
egelev

3
Michael, diyorsun ki "tüm gruplarda yapılan bu değişiklikler aslında dilin ifade gücünü değiştirmiyor; sadece belirli dil türlerinin tanımını daha özlü hale getiriyorlar". Ancak problemi, bir alt kümesi bir kez görünebilen ve başka bir alt kümesi herhangi bir sayıda görünebilen herhangi bir sayıda alt öğeye genellerseniz, XSD 1.0 çözümü, birleşimsel bir patlamaya yol açar, değil mi? XSD 1.1 çözümü temiz kalırken.
ebruchez

1
ebruchez, evet - etkileyici güç terimi kullanmak gibi, aynı değildir özlülük , kompakt , kısa ve özlü oluşu veya yönetilebilirlik . İfade gücü yalnızca "Bu biçimcilik bu dili tanımlayabilir mi?" Diye sorar. Dilbilgisinin boyutu hakkında veya bazı sözdizimsel şekerlerin onu küçültip küçültmeyeceği hakkında soru sormaz. Bahsettiğiniz kombinatoryal patlama, XSD 1.1 olmadan büyük eleman setlerinin tüm gruplarda kullanılmasının çok rahatsız edici ve çok hızlı hale geldiği anlamına gelir (ve büyük n için belleği tüketebilir). Prensipte imkansız hale geldikleri anlamına gelmez.
CM Sperberg-McQueen

49

Bu nihayet benim için çalıştı:

<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
Aslında püf noktası xsd: choice niceleyicilerle kullanmaktır <xsd: choice minOccurs = "0" maxOccurs = "unbounded">
tivo

6
Yukarıdaki örneğin, seçim öğesini çevreleyen sekans öğesi olmadan da çalıştığını belirtmeye değer olduğunu düşünüyorum.

9

Ama anladığım kadarıyla xs: seçim hala sadece tek eleman seçimine izin veriyor. Bu nedenle, MaxOccurs'u bu şekilde sınırsız olarak ayarlamak, yalnızca alt öğelerin "herhangi birinin" birden çok kez görünebileceği anlamına gelmelidir. Bu doğru mu?

Hayır. Seçim xs:choicenedeniyle oluşan her "tekrarı" için ayrı ayrı gerçekleşir maxOccurs="unbounded". Bu nedenle, gönderdiğiniz kod doğrudur ve aslında istediğinizi yazıldığı gibi yapacaktır.


@Alan tarafından sağlanan cevaba yaptığınız yorum, her şeyi güzel bir şekilde açıklıyor.
bor

3

Aşağıdaki şemanın önerdiğiniz şeye izin verdiğini görmelisiniz.

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

Bu, aşağıdaki gibi bir dosya oluşturmanıza olanak sağlar:

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

Sorunuzla uyuşuyor gibi görünüyor.


minOccursve maxOccursçocukları için 1 ile sınırlıdır xs:all.
Pavel Minaev

Pavel: Teşekkürler ... Bunu
postamı

1

Yukarıdakilerin hiçbiri işe yaramıyorsa, muhtemelen sonucunuzu bir HIPPA şemasına veya bu konuda başka herhangi bir karmaşık xsd'ye göre doğrulamanız gereken EDI trasaction üzerinde çalışıyorsunuzdur. Diyelim ki 8 REF segmenti var ve bunlardan herhangi biri herhangi bir sırada görünmek zorunda ve hepsi de gerekli değil, yani bunları 1. REF, 3. REF, 2. REF, 9. REF sırasına göre alabileceğiniz anlamına geliyor. Varsayılan durumda, EDI alımı başarısız olacaktır, çünkü varsayılan karmaşık tür

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

Öğenizi referansla çağırdığınızda durum bile karmaşıktır ve daha sonra orijinal yerindeki o öğenin kendisi oldukça karmaşıktır. Örneğin:

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

Çözüm:

Burada basitçe "dizi" yi "tümü" ile değiştirmek veya "seçim" i min / maks kombinasyonlarıyla kullanmak işe yaramaz!

İlk şey "xs:sequence" with "<xs:all>" Şimdi değiştirin , Öğeyi referans aldığınız yerde bazı değişiklikler yapmanız gerekir, İşte şuraya gidin:

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

*** Şimdi yukarıdaki segmentte sonuna şu trigger_field = "REF01 _... complete name .." trigger_value = "38" Tetikleyici değerinin farklı olacağı diğer REF segmentleri için aynısını yapın "18" "," XX "," YY "vb. Kayıt bilgilerinizin artık şöyle görünmesi için:b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


Bu, her bir öğeyi benzersiz kılacaktır, nedeni Tüm REF segmentlerinin (yukarıdaki örnek) REF01, REF02, REF03 gibi aynı yapıya sahip olmasıdır. Ve doğrulama sırasında yapı doğrulaması tamamdır, ancak değerlerin tekrarlanmasına izin vermez çünkü kalan değerleri ilk REF'in kendisinde aramaya çalışır. Tetikleyiciler eklemek, hepsini benzersiz kılar ve herhangi bir sırayla ve durumsal durumlarda geçerler (örneğin, 9 / 9'u değil, 9'u 5'i kullanın).

Umarım size yardımcı olur, bunun için neredeyse 20 saatimi harcadım.

İyi şanslar

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.