XSD Два элемента с одинаковым именем, но разными значениями атрибута

Я пытаюсь определить шаблон XSD для следующего:

<template_data>
  <given_name lang="ENG">Zluty</given_name>
  <given_name lang="CES">Žlutý</given_name>
</template_data>

Пока что я придумал

<xs:complexType name="attribute_CES">
  <xs:attribute name="lang" type="xs:string" use="required" fixed="CES"/>
</xs:complexType>

<xs:complexType name="attribute_ENG">
  <xs:attribute name="lang" type="xs:string" use="required" fixed="ENG"/>
</xs:complexType>

<xs:element name="template_data">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="given_name" type="attribute_CES"/>
      <xs:element name="given_name" type="attribute_ENG"/>          
    </xs:sequence>
  </xs:complexType>
</xs:element>

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

Насколько мне известно, вы можете потребовать, чтобы атрибут имел определенное значение с опцией fixed, и это включено в определение (сложного) типа. Поэтому, если вам нужен атрибут с другим значением, вам нужно будет определить новый тип.

Мне нужно template_data, чтобы включить оба given_name, ровно один раз с lang="CES" и ровно один раз с lang="ENG". Есть ли способ написать для этого схему проверки xsd или это невозможно (например, если ввод xml не соответствует стандартам)?


person Humungus    schedule 12.03.2014    source источник
comment
Это невозможно с XSD, поскольку это означает проверку содержимого - XSD может проверять только схему. Вам понадобится что-то вроде Schematron для достижения того, что вам нужно.   -  person Filburt    schedule 12.03.2014
comment
Действительно? Я видел базовую проверку содержимого с помощью XSD, используя restriction (w3schools.com/schema/schema_facets. asp) и с fixed в атрибутах (w3schools.com/schema/schema_simple_attributes.asp) или с типами.   -  person Humungus    schedule 12.03.2014


Ответы (1)


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

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

<xs:complexType name="languageType">
    <xs:simpleContent>
        <xs:extension base="xs:string">
            <xs:attribute name="lang" use="required">
                <xs:simpleType>
                    <xs:restriction base="xs:NMTOKEN">
                        <xs:enumeration value="ENG"/>
                        <xs:enumeration value="CES"/>
                    </xs:restriction>
                </xs:simpleType>
            </xs:attribute>
        </xs:extension>
    </xs:simpleContent>
</xs:complexType>

В languageType выше у вас есть простое содержимое (xs:string) и обязательный атрибут lang, который может иметь только два значения: ENG или CES.

Если вы хотите гарантировать, что есть ровно два элемента, вы можете ограничить это в своем определении template_data элемента с помощью minOccurs="2" и maxOccurs="2" для given_name дочернего элемента:

<xs:element name="template_data">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="given_name" type="languageType" minOccurs="2" maxOccurs="2"/>        
        </xs:sequence>
    </xs:complexType>
    ...

Теперь все еще возможно иметь два given_name элемента с одинаковым атрибутом lang="ENG". Чтобы ограничить это, мы можем добавить определение xs:key в контексте определения элемента template_data:

<xs:element name="template_data">
    <xs:complexType> ... </xs:complexType>
    <xs:key name="languageKey">
        <xs:selector xpath="given_name" />
        <xs:field xpath="@lang"/>
    </xs:key>
</xs:element>

xs:key использует вложенный given_name в качестве селектора и его атрибут lang в качестве ключевого поля. Он не разрешит дублирование полей, а это означает, что он не позволит использовать два given_name элемента с одинаковыми lang атрибутами. Поскольку вы разрешаете только два, а они могут быть только ENG или CES, один должен быть ENG, а другой CES.

Теперь этот XML-документ проверяет:

<template_data>
    <given_name lang="ENG">Zluty</given_name>
    <given_name lang="CES">Žlutý</given_name>
</template_data>

<template_data>
    <given_name lang="CES">Žlutý</given_name>
    <given_name lang="ENG">Zluty</given_name>
</template_data>

Но это не так:

<template_data>
    <given_name lang="FRA">Zluty</given_name>
    <given_name lang="CES">Žlutý</given_name>
    <given_name lang="ENG">Zluty</given_name>
</template_data>

<template_data>
    <given_name lang="ENG">Zluty</given_name>
    <given_name lang="ENG">Zluty</given_name>
</template_data>

<template_data>
    <given_name lang="ENG">Zluty</given_name>
</template_data>

<template_data>
    <given_name>Zluty</given_name>
    <given_name lang="ENG">Zluty</given_name>
</template_data>
person helderdarocha    schedule 12.03.2014
comment
Спасибо, это именно то, что я искал! Из любопытства, будет ли это работать с другим элементом, например last_name с теми же правилами, что и given_name? Я имею в виду два given_name с языками CES и ENG и два last_name с языками CES и ENG. - person Humungus; 12.03.2014
comment
Да, но вам нужно будет определить второй ключ для фамилии, поскольку ключи уникальны в пределах заданной области. Вам также придется переместить ограничения вхождения в элемент sequence, если вы хотите сохранить вместе имя и фамилию. Вы также можете заключить их в родительский элемент name и использовать только один ключ для родительского элемента. - person helderdarocha; 12.03.2014