XSD - как разрешить элементы в любом порядке любое количество раз?
Я пытаюсь создать 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:choice по-прежнему позволяет выбирать только один элемент. Следовательно, установка 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>
7 ответов
В схеме у вас есть в вашем вопросе, 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>
Альтернативная формулировка вопроса, добавленная в более поздней редакции, по-прежнему остается без ответа: как указать, что среди дочерних элементов должен быть элемент с именем 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
-группы фактически не изменяют выразительную силу языка; они только делают определение некоторых видов языков более лаконичным.
Вот что наконец-то сработало для меня:
<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>
Но из того, что я понимаю, xs:choice по-прежнему позволяет выбирать только один элемент. Следовательно, установка MaxOccurs на неограниченное значение, подобное этому, должна означать только то, что "любой" из дочерних элементов может появляться несколько раз. Это точно?
Нет. Выбор происходит индивидуально для каждого "повторения" xs:choice
что происходит из-за maxOccurs="unbounded"
, Таким образом, код, который вы опубликовали, является правильным и фактически будет выполнять то, что вы хотите, как написано.
Вы должны обнаружить, что следующая схема допускает то, что вы предложили.
<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>
Что, кажется, соответствует вашему вопросу.
Если ничего из вышеперечисленного не работает, вы, вероятно, работаете над обработкой 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 часов.
Удачи
Если у вас очень мало дочерних элементов, вы можете перечислить все возможные последовательности внутри <xs:choice>. Это дает каждой последовательности необходимую вам гибкость. Как Н! растет очень быстро, это подходит только для ~4 дочерних элементов.