Проверка XML с XSDs …, но все еще позволяет расширяемость

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

Существует ли способ сделать это?

Править:

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

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

32
задан CaffGeek 28 July 2010 в 20:16
поделиться

4 ответа

У вашей проблемы есть решение, но оно будет некрасивым. Вот почему:

Нарушение недетерминированных моделей контента

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

Модель содержимого должна быть сформирована таким образом, чтобы что во время проверки [..] каждый элемент в последовательности может быть однозначно определяется без изучения содержание или атрибуты этого элемента, и без какой-либо информации о элементы в оставшейся части последовательность.

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

Это один из наиболее обсуждаемых вопросов, наследие SGML и DTD (модели содержимого должны быть детерминированными ) и XML, который по умолчанию определяет порядок элементов важно (таким образом, попытаться сделать обратное, сделав порядок неважным, сложно).

Как уже предположил Marc_s, Relax_NG является альтернативой, которая позволяет использовать недетерминированные модели контента. Но что вы можете сделать, если вы застряли с XML-схемой W3C?

Нерабочие полу-действительные решения

Вы уже заметили, что xs: all очень ограничивает. Причина проста: применяется то же недетерминированное правило, и поэтому xs: any , min / maxOccurs больше единицы и последовательности не допускаются.

Кроме того, вы могли пробовать всевозможные комбинации выбор , последовательность и любой . Ошибка, которую выдает процессор Microsoft XSD при обнаружении такой недопустимой ситуации:

Ошибка: множественное определение элемента. ' http://example.com/Chad:SurName ' заставляет модель контента становиться двусмысленный.Модель контента должна быть сформированы таким образом, что во время валидации последовательность элементов информации, частица, содержащаяся непосредственно, косвенно или неявно в нем с который пытается проверить каждый элемент в последовательности, в свою очередь, может быть однозначно определяется без изучения содержание или атрибуты этого пункт, и без какой-либо информации о предметах в оставшейся части последовательность.

В XML-схеме О'Рейли (да, в книге есть свои недостатки) это прекрасно объяснено. К счастью, некоторые части книги доступны в Интернете. Я настоятельно рекомендую вам прочитать раздел 7.4.1.3 о Правиле атрибуции уникальных частиц , их объяснения и примеры намного яснее, чем я когда-либо смогу их понять.

Одно рабочее решение

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

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

Альтернативное решение

Я уверен, что вы это уже знаете, но порядок атрибутов по умолчанию не определен. Если все ваше содержимое относится к простым типам, вы также можете выбрать более широкое использование атрибутов.

Последнее слово

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

55
ответ дан 27 November 2019 в 20:26
поделиться

У вас должна быть возможность расширить свою схему с помощью элемент для расширяемости - подробности см. в 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: any для получения дополнительных сведений.

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

4
ответ дан 27 November 2019 в 20:26
поделиться

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

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

  1. http: //www.xfront .com / ExtensibleContentModels.html (или http://www.xfront.com/ExtensibleContentModels.pdf ) и http://www.xfront.com/VariableContentContainers.html
  2. http://www.xml.com/lpt/a/993 (или http://www.xml.com/pub/a/2002/07/03/schema_design.html )
  3. http://msdn.microsoft.com/en-us/library/ms950793.aspx
6
ответ дан 27 November 2019 в 20:26
поделиться

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

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

1
ответ дан 27 November 2019 в 20:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: