XSD - як дозволити елементи в будь-якому порядку будь-яку кількість разів?


109

Я намагаюся створити XSD і намагаюся написати визначення з наступною вимогою:

  • Дозволити вказаний дочірній елемент будь-яку кількість разів (0 до без обмежень)
  • Дозвольте дочірнім елементам бути в будь-якому порядку

Я озирнувся і знайшов різні рішення на зразок цього :

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

Але з того, що я розумію, xs: вибір все ще дозволяє лише вибір одного елемента. Отже, якщо встановити MaxOccurs таким чином, як безмежне, це повинно означати лише те, що "будь-який" з дочірніх елементів може з'являтися кілька разів. Це точно?

Якщо вищезгадане рішення є невірним, як я можу досягти того, що я заявляв вище у своїй вимозі?

EDIT : Що робити, якщо вимога наступна?

  • Елемент child1 child2 може з’являтися будь-яку кількість разів (від 0 до без обмежень)
  • Елементи повинні бути в будь-якому порядку
  • Елементи child3 та child4 повинні з’явитися рівно один раз.

Наприклад, цей xml дійсний:

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

але це не (відсутня дитина3)

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

Відповіді:


61

У схемі, у вас є запитання, child1або вона child2може з’являтися в будь-якому порядку, будь-яку кількість разів. Так це звучить як те, що ви шукаєте.

Редагувати: якби ви хотіли, щоб лише один із них з’являвся необмежену кількість разів, необмежений повинен буде перейти на елементи замість цього:

Редагувати: виправлений тип у XML.

Редагувати: Великі літери O у 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>

в основному так, я шукаю елементи child1, child2, щоб з'являтися в будь-якому порядку, в будь-яку кількість разів .. відповідь, яку ви надали тут, працює лише для одного елемента, правда? чи це також вирішує мою вимогу?
jvtech

Схема вашого запитання відповідає вашій вимозі; альтернативна схема в моїй відповіді призначена для одного елемента. Сподіваюся, що це очистить! :)
xcut

@Pavel, @xcut, Дякую за роз’яснення, див. Редаговану вимогу .. будь-які думки?
jvtech

2
jvtech: ви не можете задовольнити цю відредаговану вимогу схемою XML; єдиний спосіб досягти цього був би, якщо child3 та child4 можуть з'явитися лише наприкінці. У такому випадку вам потрібна послідовність, що містить вибір, а потім два елементи.
xcut

1
@ Daij-Djan Я також виявив, що це не працює. Спробуйте додати maxOccurs = "unbounded" на елемент вибору, щоб було дозволено більше ніж один дочірній елемент.
MikeD

107

Альтернативна постановка питання, доданого в пізнішому редагуванні, все ще не відповідає: як вказати, що серед дітей елемента має бути одне ім’я child3, одне ім’я child4та будь-яке число, назване child1або child2, без обмежень для порядку в які з’являються діти.

Це прямо визначена регулярна мова, і потрібна вам модель змісту є ізоморфною звичайному виразу, що визначає набір рядків, у яких цифри "3" і "4" зустрічаються рівно один раз, а цифри "1" і "2" 'трапляються будь-яку кількість разів. Якщо це не очевидно, як це написати, це може допомогти подумати про те, яку машину з кінцевим станом ви побудували б для розпізнавання такої мови. Він матиме щонайменше чотири різних держави:

  • початковий стан, в якому не було помічено ні "3", ні "4"
  • проміжний стан, в якому бачили "3", але не "4"
  • проміжний стан, у якому "4" було помічено, але не "3"
  • остаточний стан, в якому були помічені і "3", і "4"

Незалежно від того, в якому стані знаходиться автомат, "1" і "2" можуть бути прочитані; вони не змінюють стан машини. У початковому стані також буде прийнято "3" або "4"; у проміжних станах приймається лише "4" або "3"; в остаточному стані не приймається ні "3", ні "4". Структуру регулярного виразу найлегше зрозуміти, якщо ми спочатку визначимо регулярний вираз для підмножини нашої мови, в якій зустрічаються лише "3" та "4":

(34)|(43)

Щоб дозволити "1" або "2" виникати будь-яку кількість разів у певному місці, ми можемо вставити (1|2)*(або [12]*якщо наша мова виразів приймає це позначення). Вставивши цей вираз у всіх доступних місцях, ми отримаємо

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

Перекласти це в змістову модель просто. Основна структура еквівалентна регулярному вираженню (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>

Вставлення нуля або більше вибору child1та child2є простим:

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

Якщо ми хочемо трохи зменшити основну масу, ми можемо визначити іменовану групу для повторюваних варіантів child1і 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 деякі обмеження на all-групи були зняті, тому цю контент-модель можна визначити більш стисло:

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

Але як видно з наведених раніше прикладів, ці зміни до all-груп насправді не змінюють виразної сили мови; вони лише роблять визначення певних мов більш коротким.


3
Мені подобається XSD 1.0 xs: все альтернативно.
TWiStErRob

8
+1. Це відмінна відповідь, і вона заслуговує на більшу кількість нагород.
Крістофер Летте

1
Чудова відповідь! Мені дуже подобаються такі пояснення. Він розкриває всю логіку та міркування, що стоять за досягнення мети. Зараз я не лише знаю, як вирішити цю проблему, але навчився нового підходу до вирішення подібних проблем. Пояснити це за допомогою автоматизації кінцевого стану - дуже гарна ідея.
egelev

3
Майкл, ви говорите: "Ці зміни для всіх груп насправді не змінюють виразної сили мови; вони лише роблять визначення певних мов більш лаконічним". Але якщо ви узагальнюєте проблему на будь-яку кількість дочірніх елементів, підмножина яких може з’являтися один раз, а інша підмножина, яка може з’являтися будь-яку кількість разів, рішення XSD 1.0 приведе до комбінаторного вибуху, чи не так? Хоча розчин XSD 1.1 залишатиметься чистим.
ebruchez

1
ebruchez, так - експресивна сила , як я використовую цей термін, не те саме, як стислість , компактність , лайливість або керованість . Виразна сила запитує лише "Чи може цей формалізм визначити цю мову?" Це не запитує про розмір граматики чи про те, чи зробить якийсь синтаксичний цукор меншим. Згаданий вами комбінаторний вибух означає, що поводження з великими наборами елементів без зміни XSD 1.1 для всіх груп стає дуже неприємним дуже швидким (а для великих n може вичерпати пам'ять). Це не означає, що вони в принципі стають неможливими.
CM CM Sperberg-McQueen

49

Ось що, нарешті, спрацювало для мене:

<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
Справді, хитрість полягає у використанні xsd: вибір з кількісними показниками <xsd: вибір minOccurs = "0" maxOccurs = "без обмежень">
tivo

6
Я думаю, що варто зазначити, що наведений вище приклад працює навіть без елемента послідовності, що додає елемент вибору.

9

Але з того, що я розумію, xs: вибір все ще дозволяє лише вибір одного елемента. Отже, якщо встановити MaxOccurs таким чином, як безмежне, це повинно означати лише те, що "будь-який" з дочірніх елементів може з'являтися кілька разів. Це точно?

Ні. Вибір відбувається індивідуально для кожного "повторення" того, xs:choiceщо відбувається через maxOccurs="unbounded". Тому код, який ви опублікували, є правильним і фактично буде робити те, що вам потрібно, як написано.


Ваш коментар з відповіддю, наданою @Alan, це все добре пояснює.
бор

3

Ви повинні виявити, що наступна схема дозволяє те, що ви запропонували.

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

Це дозволить вам створити такий файл, як:

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

Який, здається, відповідає вашому питанню.


minOccursі maxOccursобмежені до 1 для дітей з xs:all.
Павло Мінаєв

Павел: Дякую ... Я це дізнався після подвійної перевірки своєї публікації, а потім відредагував її, щоб видалити xs: all
Steven_W

1

Якщо жодне з перерахованого вище не працює, ви, ймовірно, працюєте над відстеженням EDI, де вам потрібно перевірити результат щодо схеми HIPPA або будь-якого іншого складного xsd з цього питання. Вимога полягає в тому, що, скажімо, є 8 сегментів REF, і будь-який з них повинен з’являтися в будь-якому порядку, а також не всі потрібні, означає сказати, що ви можете мати їх у наступному порядку 1-й REF, 3-й REF, 2-й REF, 9-й REF. У ситуації за замовчуванням отримання EDI не вдасться, оскільки це типовий тип за замовчуванням

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

Ситуація є навіть складною, коли ви називаєте свій елемент рефрентом, і тоді цей елемент у його оригінальному місці сам по собі є досить складним. наприклад:

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

Рішення:

Тут просто замінити "послідовність" на "всі" або використовувати "вибір" комбінаціями min / max не вийде!

Перше, що замініть "xs:sequence" with "<xs:all>" зараз. Вам потрібно внести деякі зміни, звідки ви посилаєтесь на елемент, перейдіть до:

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

*** Тепер у наведеному вище сегменті додайте тригерну точку наприкінці, як це тригер_field = "REF01 _... повне ім'я ..". "," XX "," YY "тощо. Так, що інформація про ваш запис зараз виглядає так:b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


Це зробить кожен елемент унікальним, тому всі сегменти REF (вищенаведений приклад) мають таку ж структуру, як REF01, REF02, REF03. І під час перевірки перевірка структури нормальна, але вона не дозволяє значенням повторюватися, оскільки вона намагається шукати залишкові значення в першому REF. Додавання тригерів зробить їх унікальними, і вони пройдуть у будь-якому порядку та ситуаційних випадках (як-от використання 5 з 9, а не всі 9/9).

Сподіваюся, це вам допоможе, бо я витратив на це майже 20 годин.

Щасти

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.