XML-схема - определение дочерних элементов 0- * в любом порядке - PullRequest
11 голосов
/ 31 августа 2010

Я хочу определить схему 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>

Ответы [ 5 ]

30 голосов
/ 31 августа 2010

Я решил это, установив выбор и установив атрибуты 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>
8 голосов
/ 03 сентября 2010

@ Собственный ответ Торбьёрна более ясен, чем этот, но только одно небольшое изменение в вашей первоначальной попытке привело бы к тому же результату: добавление 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", и последовательность может повторяться снова и снова.

4 голосов
/ 03 сентября 2010

(Это не совсем ответ на OP, но ответ на другой предложенный ответ на вопрос OP. Как совершенно новый член, я не уверен, нарушает ли это некоторые правила или соглашения здесь, на 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> s и, таким образом, примерно удваивает LOC для этого сложного типа.

Есть ли для этого смысл?

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

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

1 голос
/ 17 апреля 2017

Это очень старая тема, но на случай, если это кому-нибудь поможет, вот что я сделал для решения проблемы. Используйте 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>
0 голосов
/ 31 августа 2010

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

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

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

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