Ответ 1
У вашей проблемы есть разрешение, но это будет не очень хорошо. Вот почему:
Нарушение моделей недетерминированного контента
Вы коснулись самой души W3C XML Schema. Что вы спрашиваете:— переменный порядок и переменные неизвестные элементы — нарушает самый сложный, но самый основополагающий принцип XSD, правило Non-Ambiguity или, более формально, Уникальное ограничение атрибутов частиц:
Модель контента должна быть сформирована таким образом что во время проверки [..] каждый элемент в последовательности может быть однозначно определяется без изучения контента или атрибутов этого элемента, и без какой-либо информации о в оставшейся части Последовательность.
В обычном английском языке: когда 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' приводит к тому, что модель контента становится неоднозначный. Модель контента должна быть что во время проверки последовательность элементов информации элемента, частица, содержащаяся непосредственно, косвенно или неявно которые пытаются проверить каждый элемент в последовательности, в свою очередь, может быть однозначно определяется без изучения содержание или атрибуты этого и без какой-либо информации о предметах в оставшейся части последовательность.
В O'Reilly XML Schema (да, у книги есть свои недостатки), это прекрасно объяснено. К счастью, части книги доступны в Интернете. Я настоятельно рекомендую вам прочитать раздел 7.4.1.3 о правиле атрибута уникального элемента, их объяснения и примеры намного яснее, чем я могу их получить.
Одно рабочее решение
В большинстве случаев можно перейти от недетерминированного дизайна к детерминированному дизайну. Это обычно выглядит не очень красиво, но это решение, если вам нужно придерживаться W3C XML Schema и/или если вы абсолютно должны разрешать нестандартные правила для вашего 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>
(или вызвать его "Свойства" или "Необязательные данные" ). Это выглядит следующим образом:
<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>
В настоящий момент это может показаться менее идеальным, но пусть оно немного возрастет. Наличие упорядоченного набора фиксированных элементов не является большой сделкой. Вы не единственный, кто будет жаловаться на этот очевидный недостаток W3C XML Schema, но, как я сказал ранее, если вам нужно его использовать, вам придется жить с его ограничениями или принять бремя разработки вокруг этих ограничений при более высокой стоимости владения.
Альтернативное решение
Я уверен, что вы это уже знаете, но порядок атрибутов по умолчанию не определен. Если весь ваш контент имеет простые типы, вы можете альтернативно выбрать более широкое использование атрибутов.
Последнее слово
Какой бы подход вы ни выбрали, вы потеряете большую достоверность ваших данных. Часто бывает лучше разрешить контент-провайдерам добавлять типы контента, но только тогда, когда это можно проверить. Это можно сделать, переключившись с lax
на strict
и сделав сами типы более строгими. Но быть слишком строгим тоже нехорошо, правильный баланс будет зависеть от вашей способности судить о случаях использования, с которыми вы столкнулись, и взвешивать это по сравнению с компромиссом определенных стратегий реализации.