Подтвердить что ты не робот

Проверка XML с помощью XSD... но все же позволяет расширяемость

Может быть, это я, но кажется, что если у вас есть XSD

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="User">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="GivenName" />
                <xs:element name="SurName" />
            </xs:sequence>
            <xs:attribute name="ID" type="xs:unsignedByte" use="required" />
        </xs:complexType>
    </xs:element>
</xs:schema>

который определяет схему для этого документа

<?xml version="1.0" encoding="utf-8" ?>
<User ID="1">
    <GivenName></GivenName>
    <SurName></SurName>
</User>

Не удалось проверить, добавили ли вы еще один элемент, скажем EmailAddress, и смешайте порядок

<?xml version="1.0" encoding="utf-8" ?>
<User ID="1">
    <SurName></SurName>
    <EmailAddress></EmailAddress>
    <GivenName></GivenName>
</User>

Я не хочу добавлять EmailAddress в документ и отмечать его необязательно.

Я просто хочу, чтобы XSD проверял минимальные требования, предъявляемые к документу.

Есть ли способ сделать это?

EDIT:

marc_s указал ниже, что вы можете использовать xs:any внутри xs:sequence, чтобы разрешить больше элементов, к сожалению, вам нужно поддерживать порядок элементов.

В качестве альтернативы я могу использовать xs:all, который не обеспечивает порядок элементов, но, увы, не позволяет мне помещать xs:any внутри него.

4b9b3361

Ответ 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 и сделав сами типы более строгими. Но быть слишком строгим тоже нехорошо, правильный баланс будет зависеть от вашей способности судить о случаях использования, с которыми вы столкнулись, и взвешивать это по сравнению с компромиссом определенных стратегий реализации.

Ответ 2

После прочтения ответа marc_s и обсуждения в комментариях я решил немного добавить.

Мне кажется, нет идеального решения вашей проблемы Чад. Существуют некоторые подходы к реализации модели расширяемого контента в XSD, но у меня есть известная реализация. Поскольку вы не писали о среде, где вы планируете использовать расширяемый XSD, я могу только рекомендовать некоторые ссылки, которые, вероятно, помогут вам выбрать способ, который может быть реализован в вашей среде:

Ответ 3

Вы можете расширить свою схему с помощью элемента <xs:any> для расширяемости - подробнее см. W3Schools.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="User">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="GivenName" />
                <xs:element name="SurName" />
                <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax" />
            </xs:sequence>
            <xs:attribute name="ID" type="xs:unsignedByte" use="required" />
        </xs:complexType>
    </xs:element>
</xs:schema>

Когда вы добавляете processContents="lax", тогда проверка .NET XML должна преуспеть на нем.

Подробнее см. Документы MSDN на xs: любые.

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

Ответ 4

Ну, вы всегда можете использовать DTD:-), за исключением того, что DTD также предписывает заказ. Валидация с "неупорядоченной" грамматикой ужасно дорога. Вы можете играть с xsd: выбором, а min и max встречается, но это, вероятно, тоже будет препятствовать. Вы также можете писать расширения XSD/производные схемы.

Как вы столкнулись с проблемой, похоже, что вы вообще не хотите XSD. Вы можете просто загрузить его, а затем проверить все, что вы хотите, с помощью XPaths, но просто протестуя против XSD, сколько лет после того, как он стал общеизвестным стандартом, действительно, действительно не собираюсь вас никуда.

Ответ 5

RelaxNG будет решать эту проблему лаконично, если вы сможете ее использовать. Детерминизм не является обязательным требованием для схем. Вы можете перевести схему RNG или RNC в XSD, но в этом случае она будет приблизительной. Будь то достаточно хорошо для вашего использования, зависит от вас.

Схема RNC для этого случая:

start = User
User = element User {
   attribute ID { xsd:unsignedByte },
   ( element GivenName { text } &
     element SurName { text } &
     element * - (SurName | GivenName) { any })
}

any = element * { (attribute * { text } | text | any)* }

Любое правило соответствует любому хорошо сформированному фрагменту XML. Поэтому для этого элемента User должен содержать элементы GivenName и SurName, содержащие текст в любом порядке, и разрешать любые другие элементы, содержащие почти что-либо.