Ошибки проверки XML с XMLSchemaSet

У меня есть следующая схема:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="MyDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Leaf" />
  <xs:complexType name = "Leaf" mixed="true">
         <xs:attribute name="ID" type="xs:string" />
  </xs:complexType>

  <xs:element name="Frame" />
  <xs:complexType name="Frame" mixed="true">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="Leaf" type ="Leaf" nillable="true"/>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="Frame" type="Frame" nillable="true"/>
    </xs:sequence>
       <xs:attribute name="ID" type="xs:string" />
  </xs:complexType>

  <xs:element name="Document">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="1" maxOccurs="1" name="Version" type="xs:string" />
        <xs:element minOccurs="0" maxOccurs="1" name="MetaData1" type="xs:string" />
        <xs:element minOccurs="0" maxOccurs="1" name="MetaData2" type="xs:string" />

        <xs:element minOccurs="1" maxOccurs="unbounded" name="Page" nillable="false">
          <xs:complexType mixed="true">
            <xs:sequence>
              <xs:element minOccurs="0" maxOccurs="unbounded" name="Frame" type="Frame" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

В основном это рекурсивная структура. Документ может иметь список страниц. Он должен содержать не менее 1 страницы. Страница состоит из списка фреймов. Кадр может иметь подкадры или листья (т. е. не может содержать подкадры). MetaData1 и MetaData2 являются необязательными и могут встречаться где угодно.

Пример XML будет следующим:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
  <Version>1.1</Version>
  <MetaData1>Somemetadata</MetaData1>
  <Page>Page1
       <Frame ID="1">Frame1
          <Frame ID="2">SubFrame1
                <Frame ID="3">SubFrame2
                      <Leaf ID="1">Alone</Leaf>
                </Frame>
               <Leaf ID="2">Alone2</Leaf>
          </Frame>
        </Frame>
        <Frame ID="3">SubFrame3
        </Frame>
 </Page>
 <MetaData2 />
</Document>

Я использую XmlReaderSettings и XmlSchemaSet для проверки XML по схеме. По какой-то причине я получаю эти 2 ошибки:

1) {"У элемента "Документ" есть недопустимый дочерний элемент "Метаданные2". Ожидается список возможных элементов: "Страница"."}

Я думаю, это потому, что он читается последовательно, тогда как в моем случае эти элементы могут появляться в любом порядке. Я попытался сделать атрибут xs:all, но он не работает с maxoccurs=unbounded. Любым другим путем ?

2) {"Элемент 'Frame' имеет недопустимый дочерний элемент 'Leaf'. Ожидается список возможных элементов: 'Frame'."}

Может ли это быть таким же, как (1)? Ошибка возникает для Leaf ID = 2

Любая помощь будет оценена по достоинству. Спасибо


person Frank Q.    schedule 19.09.2012    source источник


Ответы (1)


Вы используете Microsoft .NET, а это означает, что вы ограничены тем, что может предложить XSD 1.0. Композитор xs:all поддерживает только частицы с maxOccurs="1". Это ваша первая проблема.

Ваша схема определенно не отражает тот факт, что MetaData1 и MetaData2 могут встречаться где угодно. Leaf, Frame и Page вообще не имеют этих элементов. Так что вам придется что-то делать с этим.

Несмотря на это, вы не можете достичь именно того, чего хотите, как описано; что-то должно дать. Вы можете указать положение некоторых элементов, разрешить некоторую изменчивость среди определенных частиц или «спрятать» повторяющиеся элементы под элементом «коллекции». Страницы для страниц, рамки для рамок, листья для листьев.

Другой вариант, который я бы настоятельно рассмотрел, учитывая определение, которое вы предоставили для элементов метаданных и версии и которое не повлияет на «эквивалентный» набор данных ADO.NET (при условии, что это было бы возможно в XSD 1.0), будет использовать вместо этого атрибуты. Я проиллюстрирую этот подход. Если вы не уверены в других вариантах, дайте мне знать, и я добавлю еще несколько примеров.

Модифицированный XSD:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="MyDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:complexType name = "Leaf" mixed="true">
        <xs:attribute name="ID" type="xs:string"/>
        <xs:attributeGroup ref="metadata"/>
    </xs:complexType>

    <xs:complexType name="Frame" mixed="true">
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="Leaf" type ="Leaf" nillable="true"/>
            <xs:element name="Frame" type="Frame" nillable="true"/>
        </xs:choice>
        <xs:attribute name="ID" type="xs:string"/>
        <xs:attributeGroup ref="metadata"/>
    </xs:complexType>

    <xs:element name="Document">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="1" maxOccurs="unbounded" name="Page" nillable="false">
                    <xs:complexType mixed="true">
                        <xs:sequence>
                            <xs:element minOccurs="0" maxOccurs="unbounded" name="Frame" type="Frame"/>
                        </xs:sequence>
                        <xs:attributeGroup ref="metadata"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:attribute name="version" type="xs:string" use="required"/>
            <xs:attributeGroup ref="metadata"/>
        </xs:complexType>
    </xs:element>

    <xs:attributeGroup name="metadata">
        <xs:attribute name="metadata1" type="xs:string"/>
        <xs:attribute name="metadata2" type="xs:string"/>
    </xs:attributeGroup>
</xs:schema>

Визуализация вышеперечисленного:

QTAssistant, показывающий XSD-диаграмму

И эквивалентный набор данных ADO.NET (его проще всего использовать для подтверждения вашего описания модели):

QTAssistant, показывающий XSD как набор данных ADO.NET

Семантически эквивалентный XML, который подтвердит вышесказанное (минимально измененный, легко увидеть влияние использования вместо этого атрибутов):

<?xml version="1.0" encoding="UTF-8"?>
<Document version="1.1" metadata1="Somemetadata" metadata2="">
    <Page>Page1
        <Frame ID="1">Frame1
            <Frame ID="2">SubFrame1
                <Frame ID="3">SubFrame2
                    <Leaf ID="1">Alone</Leaf>
                </Frame>
            </Frame>
        </Frame>
        <Frame ID="3">SubFrame3
        </Frame>
    </Page>
</Document>

Схема приведенного выше XML:

Пример XML

Более сложный образец XML, показывающий действительный экземпляр:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" version="version1" metadata1="metadata11" metadata2="metadata21">
    <Page metadata1="metadata11" metadata2="metadata21">text<Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
            <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
            <Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                <Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                    <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                </Frame>
                <Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                    <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                </Frame>
            </Frame>
            <Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                <Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                    <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                </Frame>
                <Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                    <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
                </Frame>
            </Frame>
        </Frame>
    </Page>
    <Page metadata1="metadata11" metadata2="metadata21">text<Frame ID="ID1" metadata1="metadata11" metadata2="metadata21">text<Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
            <Leaf ID="ID1" metadata1="metadata11" metadata2="metadata21">text</Leaf>
        </Frame>
    </Page>
</Document>
person Petru Gardea    schedule 19.09.2012
comment
Он по-прежнему дает {Элемент «Кадр» имеет недопустимый дочерний элемент «Лист». Ожидается список возможных элементов: 'Frame'.} ошибка с вашей схемой. Посмотрите мой исходный XML, вам не хватает узла Leaf ID = 2. - person Frank Q.; 19.09.2012
comment
@ФрэнкКью. , См. обновленный пост: содержимое фрейма должно было быть неограниченным выбором Frame или Leaf. Я исправил это. - person Petru Gardea; 19.09.2012
comment
спасибо, что сработало! И последнее, как вы обеспечиваете, чтобы Frame или Leaf содержали значение Text? Если я не укажу текст с ними, он все равно пройдет проверку, тогда как я хочу ее провалить. - person Frank Q.; 19.09.2012
comment
Извините, вы не можете ограничить текстовое значение в сложном/смешанном содержании. Для этого вам придется полагаться на код .NET. - person Petru Gardea; 19.09.2012