XSD - как разрешить элементы в любом порядке любое количество раз? - PullRequest
101 голосов
/ 18 февраля 2010

Я пытаюсь создать XSD и пытаюсь написать определение со следующим требованием:

  • Разрешить указывать дочерний элемент, указанный любое количество раз (от 0 до неограниченного)
  • Разрешить дочерние элементы в любом порядке

Я оглянулся и нашел различные решения, такие как this :

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

Но из того, что я понимаю хз: выбор по-прежнему допускает только выбор одного элемента.Следовательно, установка MaxOccurs на неограниченное значение, подобное этому, должна означать, что «любой» из дочерних элементов может появляться несколько раз.Это точно?

Если вышеуказанное решение неверно, как я могу добиться того, что я изложил выше в своем требовании?

РЕДАКТИРОВАТЬ : Что делать, если требование является следующим?

  • Элемент 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>

, но это не так (отсутствует child3)

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

Ответы [ 6 ]

97 голосов
/ 18 августа 2012

Альтернативная формулировка вопроса, добавленная в более поздней редакции, по-прежнему остается без ответа: как указать, что среди дочерних элементов элемента должен быть один с именем 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 -группах фактически не изменяют выразительную силу языка; они только делают определение некоторых видов языков более кратким.

56 голосов
/ 18 февраля 2010

В схеме, которая есть в вашем вопросе, 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>
47 голосов
/ 21 апреля 2011

Вот что у меня наконец получилось:

<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>
8 голосов
/ 19 февраля 2010

Но из того, что я понимаю, xs: выбор позволяет выбирать только один элемент. Следовательно, установка MaxOccurs на неограниченное значение, подобное этому, должна означать, что «любой» из дочерних элементов может появляться несколько раз. Это точно?

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

3 голосов
/ 19 февраля 2010

Вы должны обнаружить, что следующая схема допускает то, что вы предложили.

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

Что, кажется, соответствует вашему вопросу.

1 голос
/ 15 мая 2013

Если ничего из вышеперечисленного не работает, вы, вероятно, работаете над обработкой 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>

Решение:

Здесь просто заменить «последовательность» на «все» или использовать «выбор» с комбинациями мин / макс!

Первым делом замени "xs:sequence" with "<xs:all>" Теперь вам нужно внести некоторые изменения, откуда вы ссылаетесь на элемент, Там идут:

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

*** Теперь в вышеприведенном сегменте добавьте точку запуска в конце, например: trigger_field = "REF01 _... complete name .." trigger_value = "38" Сделайте то же самое для других сегментов REF, где значение триггера будет другим, например, скажем «18», «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 часов.

Удачи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...