У вашей проблемы есть решение, но оно не будет красивым. И вот почему:
Нарушение недетерминированных моделей контента
Вы затронули саму суть XML-схемы W3C. Что вы спрашиваете & mdash; переменный порядок и переменные неизвестные элементы & mdash; нарушает самый сложный, но самый основной принцип XSD, правило Non-неоднозначность , или, более формально, ограничение уникальной принадлежности частиц :
Модель контента должна быть сформирована таким
что во время проверки [..] каждый элемент
в последовательности может быть однозначно
определяется без изучения
содержание или атрибуты этого элемента,
и без какой-либо информации о
предметы в оставшейся части
последовательность.
На обычном английском языке: когда XML проверяется и XSD-процессор обнаруживает <SurName>
, он должен иметь возможность проверить его без предварительной проверки, следует ли за ним <GivenName>
, т. Е. Без ожидания. В вашем сценарии это невозможно. Это правило существует, чтобы разрешить реализации через конечные автоматы, что должно сделать реализации довольно тривиальными и быстрыми.
Это одна из наиболее обсуждаемых проблем, которая является наследием SGML и DTD (модели контента должны быть детерминированными ) и XML, которые по умолчанию определяют порядок элементов важен (таким образом, попытка сделать обратное, сделать заказ неважным, труден).
Как уже предлагал Marc_s, Relax_NG является альтернативой, которая допускает недетерминированные модели контента. Но что вы можете сделать, если застряли в XML-схеме W3C?
Нерабочие полуправильные решения
Вы уже заметили, что xs:all
очень ограничительно. Причина проста: применяется одно и то же недетерминированное правило, и поэтому xs:any
, min/maxOccurs
больше единицы, и последовательности не допускаются.
Кроме того, вы, возможно, пробовали всевозможные комбинации choice
, sequence
и any
. Ошибка, которую выдает процессор Microsoft XSD при возникновении такой недопустимой ситуации:
Ошибка: множественное определение элемента
«http://example.com/Chad:SurName'
заставляет модель контента становиться
неоднозначный. Модель контента должна быть
сформирован так, что во время проверки
последовательность элементов информации об элементе,
частица содержала непосредственно,
косвенно или косвенно
который пытается проверить каждый элемент
в последовательности в свою очередь может быть
однозначно определяется без изучения
содержание или атрибуты этого
пункт, и без какой-либо информации
о предметах в оставшейся части
последовательность.
В XML-схеме О'Рейли (да, у книги есть свои недостатки), это прекрасно объяснено. К счастью, части книги доступны онлайн. Я настоятельно рекомендую вам прочитать раздел 7.4.1.3 об уникальном правиле атрибуции частиц , их объяснения и примеры гораздо яснее, чем я когда-либо смогу их получить.
Один рабочий раствор
В большинстве случаев возможно перейти от недетерминированного дизайна к детерминированному дизайну. Обычно это выглядит не очень красиво, но это решение, если вам нужно придерживаться XML-схемы W3C и / или если вам абсолютно необходимо разрешить нестрогие правила для вашего XML. Кошмар в вашей ситуации заключается в том, что вы хотите применить одну вещь (2 предопределенных элемента) и в то же время хотите, чтобы она была очень свободной (порядок не имеет значения и , все может быть между, до и после ). Если я не попытаюсь дать вам хороший совет, а просто приведу вас непосредственно к решению, оно будет выглядеть следующим образом:
<xs:element name="User">
<xs:complexType>
<xs:sequence>
<xs:any minOccurs="0" processContents="lax" namespace="##other" />
<xs:choice>
<xs:sequence>
<xs:element name="GivenName" />
<xs:any minOccurs="0" processContents="lax" namespace="##other" />
<xs:element name="SurName" />
</xs:sequence>
<xs:sequence>
<xs:element name="SurName" />
<xs:any minOccurs="0" processContents="lax" namespace="##other" />
<xs:element name="GivenName" />
</xs:sequence>
</xs:choice>
<xs:any minOccurs="0" processContents="lax" namespace="##any" />
</xs:sequence>
<xs:attribute name="ID" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
Код выше на самом деле просто работает . Но есть несколько предостережений. Первый - xs:any
с ##other
в качестве пространства имен. Вы не можете использовать ##any
, за исключением последнего, потому что это позволило бы использовать такие элементы, как GivenName
, вместо этого, и это означает, что определение User
становится неоднозначным.
Второе предостережение: если вы хотите использовать этот трюк с более чем двумя или тремя, вам придется записать все комбинации. Технический кошмар. Вот почему я придумываю следующее:
Предлагаемое решение, вариант контейнера с переменным содержимым
Измените свое определение. Это имеет преимущество в том, чтобы быть более понятным для ваших читателей или пользователей. Он также имеет преимущество в том, что его легче обслуживать. Целая строка решений объяснена на XFront здесь , менее читаемая ссылка, которую вы, возможно, уже видели в посте от Олега. Это отличное чтение, но в большинстве случаев не учитывается минимальное требование наличия двух элементов внутри контейнера переменного содержимого.
В настоящее время наилучшим подходом для вашей ситуации (который случается чаще, чем вы можете себе представить) является разделение ваших данных между обязательными и необязательными полями. Вы можете добавить элемент <Required>
или сделать наоборот, добавить элемент <ExtendedInfo>
(или назвать его Properties или OptionalData ). Это выглядит следующим образом:
<xs:element name="User2">
<xs:complexType>
<xs:sequence>
<xs:element name="GivenName" />
<xs:element name="SurName" />
<xs:element name="ExtendedInfo" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax" namespace="##any" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
В данный момент это может показаться не совсем идеальным, но пусть немного вырастет. Наличие упорядоченного набора фиксированных элементов не так уж сложно. Вы не единственный, кто будет жаловаться на очевидный недостаток XML-схемы W3C, но, как я уже говорил ранее, если вам придется использовать его, вам придется смириться с его ограничениями или принять бремя разработки вокруг этих ограничений при более высокой стоимости владения.
Альтернативное решение
Я уверен, что вы уже знаете это, но порядок атрибутов по умолчанию не определен. Если весь ваш контент имеет простые типы, вы можете выбрать более широкое использование атрибутов.
Последнее слово
Какой бы подход вы ни выбрали, вы потеряете много проверяемых данных. Зачастую поставщикам контента разрешается добавлять типы контента, но только тогда, когда это можно проверить. Это можно сделать, переключившись с обработки lax
на strict
и сделав сами типы более строгими. Но быть слишком строгим также нехорошо, правильный баланс будет зависеть от вашей способности оценивать варианты использования, с которыми вы сталкиваетесь, и взвешивать их в сравнении с компромиссами определенных стратегий реализации.