Xml-схема - определяет дочерние элементы 0- * в любом порядке

Я хочу определить схему xml, в которой элемент Connectors имеет 0- * дочерние элементы. Любая последовательность, ассоциация или сообщение в любом порядке и от 0 до много раз. То есть.

<Connectors>
    <Sequence />
    <Association />
    <Message />
    <Sequence />
    <Sequence />
    <Message />
    <Message />
    <Association />
</Connectors>

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

<xs:element name="Connectors">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Association" minOccurs="0" maxOccurs="unbounded" />
            <xs:element ref="Message" minOccurs="0" maxOccurs="unbounded" />
            <xs:element ref="Sequence" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

Ответ 1

Я решил это, установив выбор и установив атрибуты minOccurs и maxOccurs.

<xs:element name="Connectors">
    <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element ref="Association" />
            <xs:element ref="Message" />
            <xs:element ref="Sequence" />
        </xs:choice>
    </xs:complexType>
</xs:element>

Ответ 2

@Собственный ответ Torbjörn более ясен, чем этот, но только одно небольшое изменение в вашей первоначальной попытке привело бы к такому же результату: добавление maxOccurs="unbounded" в элемент <xs:sequence>.

<xs:element name="Connectors">
    <xs:complexType>
        <xs:sequence maxOccurs="unbounded">
            <xs:element minOccurs="0" name="Association" />
            <xs:element minOccurs="0" name="Message" />
            <xs:element minOccurs="0" name="Sequence" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

Случайный порядок гарантирован, потому что каждый элемент имеет minOccurs="0", и последовательность может повторяться снова и снова.

Ответ 3

(Это не совсем ответ OP, но ответ на другой предложенный ответ на вопрос OP. Как совершенно новый memeber, я не уверен, что это нарушает некоторые правила или соглашения здесь, на stackoverflow.com. Извините. )

Как пользователь @Richard написал в своем ответе:

К сожалению, в XML-схеме нет способа определить "этот набор дочерних элементов в любом порядке, но каждый из них происходит хотя бы один раз".

Вы застряли либо с определенным порядком, либо с одним из множества (возможно, повторяющимся).

Верно, что нет тегов или атрибутов, которые особенно допускают такие структуры, однако цитируемый текст теоретически не соответствует действительности, хотя решение становится быстро огромным по мере увеличения количества элементов. Написание схемы для такой структуры с несколькими элементами является трудоемким, подверженным ошибкам и сложным в обслуживании. Поэтому, несмотря на то, что существует решение, практически реализовать его невозможно или стоит.

В оригинальном постере появился набор из трех случайных элементов. Правильное решение было простым, потому что ни один из элементов не был обязательным. Но даже в таком случае, при таком небольшом наборе элементов, заставляя каждый из элементов появляться хотя бы один раз, все еще достаточно легко реализовать. Пример кода ниже

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <!-- Schema for 3 elements with random order.
        Each element must appear at least once. -->

    <xs:element name="Association" type="xs:string"/>
    <xs:element name="Message" type="xs:string"/>
    <xs:element name="Sequence" type="xs:string"/>

    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="unbounded" name="Connectors" type="unordered-3-group" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="unordered-3-group">
    <!-- state level 0 -->
        <xs:group ref="Connectors-state-0"/>
    </xs:complexType>

    <xs:group name="Connectors-state-0">
        <xs:sequence>
            <!-- Empty, no previous elements
            <xs:choice minOccurs="0" maxOccurs="unbounded">
            </xs:choice> -->
            <xs:choice>
                <xs:sequence>
                    <xs:element ref="Association"/>
                    <xs:group ref="Connectors-state-1a"/>
                </xs:sequence>
                <xs:sequence>
                    <xs:element ref="Message"/>
                    <xs:group ref="Connectors-state-1b"/>
                </xs:sequence>
                <xs:sequence>
                    <xs:element ref="Sequence"/>
                    <xs:group ref="Connectors-state-1c"/>
                </xs:sequence>
            </xs:choice>
        </xs:sequence>
    </xs:group>

    <xs:group name="Connectors-state-1a">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="Association"/>
            </xs:choice>
            <xs:choice>
                <xs:sequence>
                    <xs:element ref="Message" />
                    <xs:group ref="Connectors-state-2a"/>
                </xs:sequence>
                <xs:sequence>
                    <xs:element ref="Sequence" />
                    <xs:group ref="Connectors-state-2b"/>
                </xs:sequence>
            </xs:choice>
        </xs:sequence>
    </xs:group>

    <xs:group name="Connectors-state-1b">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="Message"/>
            </xs:choice>
            <xs:choice>
                <xs:sequence>
                    <xs:element ref="Association" />
                    <xs:group ref="Connectors-state-2a"/>
                </xs:sequence>
                <xs:sequence>
                    <xs:element ref="Sequence" />
                    <xs:group ref="Connectors-state-2c"/>
                </xs:sequence>
            </xs:choice>
        </xs:sequence>
    </xs:group>

    <xs:group name="Connectors-state-1c">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="Sequence"/>
            </xs:choice>
            <xs:choice>
                <xs:sequence>
                    <xs:element ref="Association" />
                    <xs:group ref="Connectors-state-2b"/>
                </xs:sequence>
                <xs:sequence>
                    <xs:element ref="Message" />
                    <xs:group ref="Connectors-state-2c"/>
                </xs:sequence>
            </xs:choice>
        </xs:sequence>
    </xs:group>

    <xs:group name="Connectors-state-2a">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="Association"/>
                <xs:element ref="Message"/>
            </xs:choice>
            <xs:choice>
                <xs:sequence>
                    <xs:element ref="Sequence" />
                    <xs:group ref="Connectors-state-3a"/>
                </xs:sequence>
            </xs:choice>
        </xs:sequence>
    </xs:group>

    <xs:group name="Connectors-state-2b">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="Association"/>
                <xs:element ref="Sequence"/>
            </xs:choice>
            <xs:choice>
                <xs:sequence>
                    <xs:element ref="Message" />
                    <xs:group ref="Connectors-state-3a"/>
                </xs:sequence>
            </xs:choice>
        </xs:sequence>
    </xs:group>

    <xs:group name="Connectors-state-2c">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="Message"/>
                <xs:element ref="Sequence"/>
            </xs:choice>
            <xs:choice>
                <xs:sequence>
                    <xs:element ref="Association" />
                    <xs:group ref="Connectors-state-3a"/>
                </xs:sequence>
            </xs:choice>
        </xs:sequence>
    </xs:group>

    <xs:group name="Connectors-state-3a">
        <xs:sequence>
            <xs:choice minOccurs="0" maxOccurs="unbounded">
                <xs:element ref="Association"/>
                <xs:element ref="Message"/>
                <xs:element ref="Sequence"/>
            </xs:choice>
            <!-- Empty, no new elements
            <xs:choice>
                <xs:sequence>
                </xs:sequence>
            </xs:choice> -->
        </xs:sequence>
    </xs:group>

</xs:schema>

Connectors используется как контейнер, подобный OP. Отдельный элемент root позволяет нескольким Connector только упростить тестирование различных комбинаций.

Имитация различных состояний с элементами группы

Я отредактировал этот ответ и обновил код. Новый - длиннее, но это довольно ясный пример использования государственного дизайна схемы. Код следует за разными фазами конечного автомата, которые могут подтвердить эту проблему. Все состояния представлены как элементы <xs:group>, и каждая группа ссылается на другие группы, которые представляют все возможные следующие состояния. Все элементы <xs:group> подчиняются тем же правилам для своей структуры. Группы имеют последовательность из двух вариантов. Первый <xs:choice> является неограниченным повторением уже увиденных элементов. Второй <xs:choice> содержит последовательности всех возможных новых элементов после ссылки на группу, которая представляет следующее состояние.

Сложность задачи

Случай из N элементов может быть проверен с помощью детерминированной машины конечного состояния, которая имеет 2 ^ N различных состояний (включая начальное состояние). Состояния будут формировать N разных уровней, а количество состояний на каждом уровне соответствует биномиальным коэффициентам, то есть количество состояний на разных уровнях составляет "n над k", где "n" представляет количество различных элементов, а "k" представляет собой глубину уровня. Поскольку добавление еще одного элемента удваивает количество необходимых состояний, он также удваивает число <xs:group> и, следовательно, примерно удваивает LOC для этого сложного типа.

Используется ли это для использования?

Может быть... или нет. Вручную писать и особенно обновлять такую ​​структуру для больших наборов элементов, вероятно, необоснованно. Однако, поскольку все группы имеют схожую структуру, должно быть относительно легко программно генерировать соответствующий код XML-схемы для всей структуры complexType. Один из способов сделать это, который приходит мне в голову, - это функция, которая принимает два списка в качестве параметров, видимых и невидимых элементов, а затем добавляет все увиденные элементы в первый элемент <xs:choice>, и для каждого невидимого элемента создается переход к соответствующему новому состоянию а затем называет себя для каждого нового ссылочного состояния.

Имейте в виду, что даже если генерация кода устраняет боль от ручного отслеживания всей структуры, на больших элементах размер кода будет настолько большим, чтобы размер был не более разумным. Набор из 14 элементов требует 2 ^ 14 = 16383 групп, а на уровне глубины 7 существует максимум (14 над 7) = 3432 параллельных групп состояний, каждая группа имеет 39 элементов (= чуть более 40 LOC). Нет, ты не хочешь ничего подобного. В таких случаях вы должны начать поиск другого подходящего языка определения схемы.

Ответ 4

К сожалению, в XML-схеме нет практического способа определить "этот набор дочерних элементов в любом порядке, но каждый из них происходит по крайней мере один раз".

Вы застряли либо с определенным порядком, либо с одним из множества (возможно, повторяющимся).

РЕДАКТИРОВАТЬ: Нет практического способа, ручное создание каждой возможной последовательности возможно и будет работать, но комбинаторный взрыв быстро выйдет из-под контроля.

Ответ 5

Это очень старый поток, но в случае, если это может помочь любому, вот что я сделал для решения проблемы. Используйте xsd: all и установите minOccurs = "0" для любых дочерних элементов, которые можно опустить:

<xs:element name="Connectors">
    <xs:complexType>
        <xs:all>
            <xs:element name="Association" minOccurs="0"/>
            <xs:element name="Message" minOccurs="0"/>
            <xs:element name="Sequence"  minOccurs="0"/>
        </xs:all>
    </xs:complexType>
</xs:element>