XSD 1.1 Проверить, существует ли атрибут в другом элементе

У меня есть 2 основных раздела в моем XML-файле Sequence и StateRelations. Раздел Sequence определяется как. Элемент Transition должен быть уникальным на основании его 4 свойств, как определено ниже.

<xs:element name="Transition">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Element1" minOccurs="0" maxOccurs="1"/>
            <xs:element ref="Element2" minOccurs="0" maxOccurs="1"/>
            <xs:element ref="Element3" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="stateName" type="xs:string" use="required"/>
        <xs:attribute name="A" type="xs:string" use="required"/>
        <xs:attribute name="B" type="xs:string" use="required"/>
        <xs:attribute name="C" type="xs:string" use="optional"/>
    </xs:complexType>
</xs:element>
<xs:element name="Sequence">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Transition" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="optional"/>
        <xs:attribute ref="xml:base"/>
    </xs:complexType>
    <xs:unique name="uniqueTransition">
        <xs:selector xpath=".//Transition"/>
        <xs:field xpath="@stateName"/>
        <xs:field xpath="@A"/>
        <xs:field xpath="@B"/>
        <xs:field xpath="@C"/>
    </xs:unique>
</xs:element>

и раздел StateRelations определяется следующим образом. «stateName1» на самом деле является внешним ключом (keyref), который связан с «stateName» (ключом) перехода. Примечание. Элемент отношения фактически рекурсивен.

<xs:element name="Relation">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="stateName1" type="xs:string" use="required"/>
    </xs:complexType>
</xs:element>
<xs:element name="StateRelations">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="optional"/>
        <xs:attribute ref="xml:base"/>
    </xs:complexType>
</xs:element>

Проблема возникает в следующем сценарии. Поскольку Transition имеет уникальное ограничение, основанное на 4 атрибутах, следующий XML действителен.

<Transition stateName="S3" A="a1" B="b1" C="c"/>
<Transition stateName="S3" A="a" B="b" C="c"/>

Как видите, stateName = S3 может повторяться несколько раз. Но это повторение нарушает отношения первичного и внешнего ключа между переходом и отношениями. Причина: stateName может повторяться в переходах. Теперь у нас здесь конфликт. Моей конечной целью было бы иметь

  1. Уникальные последовательности на основе 4 атрибутов

  2. и каждое stateName1 в StateRelations должно быть действительным stateName, определенным в Transitions.

До сих пор я знаю, что key-keyref не будет работать в моем сценарии, поэтому я начал изучать assert, но не могу заставить его работать. Я пробовал следующее, но, похоже, ничего не работает.

    <xs:element name="Relation">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="stateName1" type="xs:string" use="required"/>

        <xs:assert test="matches( .//Transition/@stateName , @stateName1 )"/>
        <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, @stateName1)]" />
        <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, string( @stateName1 ))]/@stateName = string(@stateName1) "/>

    </xs:complexType>
</xs:element>

РЕДАКТИРОВАТЬ: вот XSD (я опустил некоторые детали). Теперь я хочу как-то проверить, что /Replay/StateRelations/Relation/@stateName1 существует в /Replay/Sequence/Transition/@stateName. Я не могу использовать key / keyref, потому что /Replay/Sequence/Transition/@stateName не будет уникальным.

<Replay>
   <xs:element name="Relation">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="stateName1" type="xs:string" use="required"/>
        <xs:assert test="matches( .//Transition/@stateName , @stateName1 )"/>
        <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, @stateName1)]" />
        <xs:assert test="/Replay/Sequence/Transition[contains(@stateName, string( @stateName1 ))]/@stateName = string(@stateName1) "/>
    </xs:complexType>
</xs:element>
<xs:element name="StateRelations">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Relation" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="optional"/>
        <xs:attribute ref="xml:base"/>
    </xs:complexType>
</xs:element>

<xs:element name="Transition">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Element1" minOccurs="0" maxOccurs="1"/>
            <xs:element ref="Element2" minOccurs="0" maxOccurs="1"/>
            <xs:element ref="Element3" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="stateName" type="xs:string" use="required"/>
        <xs:attribute name="A" type="xs:string" use="required"/>
        <xs:attribute name="B" type="xs:string" use="required"/>
        <xs:attribute name="C" type="xs:string" use="optional"/>
    </xs:complexType>
</xs:element>
<xs:element name="Sequence">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Transition" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="optional"/>
        <xs:attribute ref="xml:base"/>
    </xs:complexType>
    <xs:unique name="uniqueTransition">
        <xs:selector xpath=".//Transition"/>
        <xs:field xpath="@stateName"/>
        <xs:field xpath="@A"/>
        <xs:field xpath="@B"/>
        <xs:field xpath="@C"/>
    </xs:unique>
</xs:element>
</Replay>

person Behroz Sikander    schedule 24.02.2016    source источник


Ответы (1)


У меня проблемы с разработкой структуры верхнего уровня вашего документа. Судя по путям в ваших нерабочих утверждениях, я полагаю, что ваш элемент верхнего уровня - это Replay, и у него есть одна ветка /Replay/Sequence/Transition и, возможно, другая отдельная ветка /Replay/StateRelations/Relation?

В этом случае ограничение, определяющее связь между Transition и Relation, должно быть определено на уровне общего предка, которым является Replay. Вы можете определить его, используя либо key / keyref на этом уровне, либо используя утверждения, но в любом случае ограничения, влияющие на два разных элемента, всегда должны быть определены на уровне общего предка: потому что это дерево, основанное на этом предке, которое является самым маленьким я -содержащая часть документа недействительна.

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

person Michael Kay    schedule 24.02.2016
comment
Да, мой элемент верхнего уровня - это Replay. Вы совершенно правы. Спасибо. Однажды я переместил свое утверждение на уровень воспроизведения, и оно сработало нормально. Единственная проблема в том, что я не могу использовать key / keyref, потому что stateName в переходах не уникален. Итак, поскольку assertion - мой единственный вариант, и я должен определить его вне тега Relation, должен ли я использовать какой-то цикл for в XPath, чтобы проверить, существуют ли имена состояний, определенные в Relation, в Transition? - person Behroz Sikander; 24.02.2016
comment
Извините, я не думаю, что понимаю вашу структуру достаточно хорошо, чтобы понять, почему использование key / keyRef является проблемой. Когда вы говорите о циклах в XPath, это для key / keyRef или для утверждений? XPath, конечно, не имеет циклов, он полностью декларативен и работает с наборами узлов. - person Michael Kay; 24.02.2016
comment
Извините за непонятность. Я обновил свой вопрос. - person Behroz Sikander; 25.02.2016