Это можно решить несколькими способами, некоторые лучше, чем другие
Решение с использованием assert, но не лучшее...
В XSD 1.1 это можно сделать с помощью файла <xs:assert>
. В идеале утверждение должно быть размещено на ссылочном элементе <Restriction>
, тогда будет очевидно, какой <Restriction>
недействителен.
Однако, поскольку <xs:assert>
не может получить доступ к значениям выше в дереве, <xs:assert>
должен быть достаточно высоким, чтобы <Restriction>
и <Variable>
находились в пределах его области действия (дочерние элементы). Это было бы хорошо, но теперь вам нужно написать общее правило, которое, если оно не сработает, не даст много обратной связи — оно просто сообщит вам, что один или несколько из <Restriction>
недействительны.
Вот очень быстрый образец для демонстрации.
![Визуальное представление схемы, созданное с помощью Liquid XML Studio](https://i.stack.imgur.com/CRBdl.png)
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid XML 2017 Developer Bundle Edition 15.0.0.0 (https://www.liquid-technologies.com)-->
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="base">
<xs:complexType>
<xs:sequence>
<xs:element name="var" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="Usage" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:assert test="count(Usage[not(./text() = ../var/text())]) = 0" />
</xs:complexType>
</xs:element>
</xs:schema>
Пример XML
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid XML 2016 Developer Bundle Edition 14.1.4.6649 (https://www.liquid-technologies.com) -->
<base xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Schema.xsd">
<var>var1</var>
<var>var2</var>
<var>var4</var>
<Usage>var1</Usage>
<Usage>var2</Usage>
<Usage>var3</Usage><!-- INVALID -->
</base>
Сообщение об ошибке (через Saxon)
(10:7) Критическое cvc-утверждение: оценка утверждения ('count(Usage[not(./text() = ../var/text())]) = 0') для элемента 'base' по типу схемы' #AnonType_base' не удалось.
Лучшее решение с использованием Key/KeyRef
Это дружественно к XSD 1.0 и работает очень хорошо. Он сообщает вам, есть ли у вас повторяющиеся имена переменных, а также если ссылка на имя переменной недействительна, указывая вам на реальную проблему.
![Визуальное представление ключевой схемы keyref из Liquid XML Studio](https://i.stack.imgur.com/IpGNL.png)
<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid XML 2017 Developer Bundle Edition 15.0.0.0 (https://www.liquid-technologies.com)-->
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="base">
<xs:complexType>
<xs:sequence>
<xs:element name="Variables">
<xs:complexType>
<xs:sequence>
<xs:element name="Variable" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="name" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Restrictions">
<xs:complexType>
<xs:sequence>
<xs:element name="Restriction" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="variable" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:key name="VarDef">
<xs:selector xpath="./Variables/Variable" />
<xs:field xpath="@name" />
</xs:key>
<xs:keyref name="VarRef" refer="VarDef">
<xs:selector xpath="./Restrictions/Restriction" />
<xs:field xpath="@variable" />
</xs:keyref>
</xs:element>
</xs:schema>
Пример XML
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid XML 2017 Developer Bundle Edition 15.0.0.0 (https://www.liquid-technologies.com) -->
<base xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SchemaKeyRef.xsd">
<Variables>
<Variable name="var1"></Variable>
<Variable name="var2"></Variable>
<Variable name="var3"></Variable>
</Variables>
<Restrictions>
<Restriction variable="var1">string</Restriction>
<Restriction variable="var2">string</Restriction>
<Restriction variable="UNKNOWN">string</Restriction>
</Restrictions>
</base>
Теперь генерируемая ошибка стала более конкретной, что значительно упрощает отладку проблемы.
Ошибка из .Net (номер строки является неверным ограничением)
(12:10) Ошибка Последовательность клавиш «НЕИЗВЕСТНО» в «VarDef» Keyref не может ссылаться на какой-либо ключ.
Ошибка от Saxon (номер строки является содержащей элементной базой)
(14:7) Критическое cvc-identity-constraint.4.3: Ключ «VarRef» со значением «UNKNOWN» не найден для ограничения идентичности элемента «base».
06.09.2016