Уникальное ограничение XSD на атрибут элементов родственного типа определенного типа

У меня есть XML-документ, структурированный как Q & A, который следует за следующим форматом (отредактирован для ясности):

<question>
    <answer id="1">
        <question>
            <answer id="1"/>
            <answer id="2"/>
            <answer id="3"/>
        </question>
    </answer>
    <answer id="2">
        <question>
            <answer id="1"/>
            <answer id="2"/>
        </question>
    </answer>
</question>

Мой XSD выглядит так:

<xs:element name="question">
     <xs:complexType>
        <xs:sequence>
            <xs:element name="answer" type="answerType" minOccurs="2" maxOccurs="unbounded">
            </xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:unique name="AnswerIdUnique">
        <xs:selector xpath="./*" />
        <xs:field xpath="@id" />
    </xs:unique>
</xs:element>

<xs:complexType name="answerType">
    <xs:sequence>
        <xs:element ref="question" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
    <xs:attribute name="id" type="xs:token" use="required" />
</xs:complexType>

Это, конечно, больше, чем то, что вы видите выше, но это иллюстрирует мою проблему. Мне нужно, чтобы атрибут id на элементах answer был уникальным среди братьев и сестер. Определенный выше XSD обеспечивает уникальность атрибутов id среди элементов sibling, но он не различает тип элемента. Я попробовал различные селекторы и поля в уникальном ограничении, но не нашел комбинацию, которая работает. Любые предложения?

Ответ 1

Просто измените селектор на <xs:selector xpath="answer"/>, и все будет в порядке. В общем, полезно избегать XPaths, например .//*, если только по соображениям производительности.

Это XML-схема для образца XML, который вы указали, я думаю, работает так, как вы хотите:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="question" type="questionType">
        <xs:unique name="AnswerIdUnique">
            <xs:selector xpath="answer"/>
            <xs:field xpath="@id"/>
        </xs:unique>
    </xs:element>
    <xs:complexType name="questionType">
        <xs:sequence>
            <xs:element name="answer" type="answerType" minOccurs="2" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="answerType">
        <xs:sequence>
            <xs:element ref="question" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
        <xs:attribute name="id" type="xs:token" use="required"/>
    </xs:complexType>
</xs:schema>

Ваш опубликованный XML проверяет правильность вышеизложенного; дублирование любого идентификатора ответа сестры приводит к ошибке проверки. Например, следующий XML:

<question> 
    <answer id="1"> 
        <question> 
            <answer id="1"/> 
            <answer id="2"/> 
            <answer id="1"/> 
        </question> 
    </answer> 
    <answer id="1"> 
        <question> 
            <answer id="1"/> 
            <answer id="2"/> 
        </question> 
    </answer> 
</question> 

При проверке (в QTAssistant должно быть похоже на сообщение в Visual Studio, поскольку оно основано на той же технологии), это ошибки:

Error occurred while loading [], line 6 position 5
There is a duplicate key sequence '1' for the 'AnswerIdUnique' key or unique identity constraint.
Error occurred while loading [], line 9 position 3
There is a duplicate key sequence '1' for the 'AnswerIdUnique' key or unique identity constraint.
Document1.xml is invalid.

Ниже приведен скриншот от Visual Studio 2010, показывающий приведенную выше проверку XML против XSD, который я опубликовал; в то время как проблемы непреднамеренно сообщаются как предупреждения, они, тем не менее, сообщаются.

VS2010 showing unique constraint errors

Я случайно выбрал онлайн-валидатор (http://xsdvalidation.utilities-online.info/) и подтвердил те же XML и XSD, которые я опубликовал; ошибка сообщается как:

org.xml.sax.SAXParseException: Duplicate unique value [1] declared for identity constraint of element "question".org.xml.sax.SAXParseException: Duplicate unique value [1] declared for identity constraint of element "question".

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

UPDATE: И XSD с пространствами имен:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://localhost" xmlns="http://localhost" targetNamespace="http://localhost" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="question" type="questionType">
        <xs:unique name="AnswerIdUnique">
            <xs:selector xpath="tns:answer"/>
            <xs:field xpath="@id"/>
        </xs:unique>
    </xs:element>
    <xs:complexType name="questionType">
        <xs:sequence>
            <xs:element name="answer" type="answerType" minOccurs="2" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="answerType">
        <xs:sequence>
            <xs:element ref="question" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
        <xs:attribute name="id" type="xs:token" use="required"/>
    </xs:complexType>
</xs:schema>

Обратите внимание на введение префикса tns и его использование в селекторе.