Схема XML: ссылка на иерархически нижний элемент
Моя структура XML выглядит следующим образом:
ROOT
|_ SetOfBandC (*)
| |_ SetOfB (1)
| | |_ ElementB (*)
| | |_ ElementB__Key
| |_ SetOfC (1)
| |_ ElementC (*)
| |_ ElementC__Key
|_ ElementD (*)
|
|_ SetOfBandC__Key
|_ ElementD__Key
|
|_ ElementD->SetOfBandC__Keyref
|_ ElementD->ElementB__Keyref
В этой структуре я могу иметь несколько SetOfBandC
а также несколько ElementB
а также ElementC
, но только 1 SetofB
а также SetOfC
для каждого SetOfBandC
,
Проблема в том, что ElementD
имеет ключевую ссылку на конкретный SetOfBandC
и еще один, ссылающийся на ElementB
этого набора, но валидатор XML при проверке ElementD->ElementB__Keyref
действительность он ищет только в последнем SetOfBandC
и не во всех или, что лучше, в той, на которую ссылается ElementD->SetOfBandC__Keyref
, Так когда ElementD->ElementB__Keyref
ссылается на ElementB
который не в последнем SetOfBandC
проверка не будет работать.
Вот мой ElementD->ElementB__Keyref
:
<xs:keyref name="ElementD->ElementB__Keyref" refer="tns:ElementB__Key ">
<xs:selector xpath="tns:ElementD" />
<xs:field xpath="@elementD_ref" />
</xs:keyref>
И мой ElementB__Key
:
<xs:key name="ElementB__Key">
<xs:selector xpath="tns:ElementB" />
<xs:field xpath="@elemB_name" />
</xs:key>
Где tns - мое целевое пространство имен. Что мне не хватает?
PS: имена в моем коде разные и их нет ->
в них.
2 ответа
Я думаю, что проблема заключается в объеме ключей.
Насколько я понимаю, узел глобально идентифицируется не только по имени узла, но и по имени, которому принадлежит nffg. Таким образом, это глобально составной ключ: политика ссылается на узел с именем nffg, а также именем узла. В текущей схеме keyRef
Однако политики в них ссылаются только на эти два ключа независимо друг от друга, поэтому XML-схема не знает, что они идут вместе.
Возможно, выходом было бы использование глобально уникальных имен узлов, сделанных из префикса ключа узла с ключом nffg, например Nffg1-Node1
и использовать это вместо этого в качестве единственного ключевого ссылки в политике. Если вы также хотите убедиться, что ссылка ссылается на узел источника и назначения в пределах одного и того же nffg, вам могут потребоваться два определения ключа для node
: один глобальный для политики keyRef
с (под allNffgsAndPolicies
), один местный к NFFG (под nffg
) по ссылке keyRef
s.
Немного другая альтернатива - повторить nffgName
атрибут в узлах, и использовать это вместе с неизменным nodeName
атрибут как глобальный составной ключ для узлов - используя два xs:field
элементы в ключе - которые вы можете использовать в политиках. Вы должны быть в состоянии гарантировать, что узел локальный nffgname
атрибут соответствует атрибуту родительского nffg с key
с и keyRef
также.
Бонусный вопрос: это все еще не объясняет, почему, с оригинальным экземпляром и схемой, Node3
отклонено, но другие значения принимаются. Я ожидал, что ошибка будет сгенерирована на значении, присутствующем в обоих поддеревьях. В спецификации конфликтующие ключи между дочерними элементами удаляются из таблицы узлов, однако в этом случае такой ключ, как Node2
будет противоречивым, как это на обоих поддеревьях, но не Node3
как это только появляется в первом поддереве. Однако здесь происходит обратное, и только последняя таблица узлов ребенка, кажется, рассматривается для включения в таблицу узлов верхнего уровня.
Если вы можете использовать XML-схему 1.1, следующее должно работать без изменения XML-документов или самой структуры схемы.
Удалить оба
keyRef
с дляtns:policy
Вместо этого используйте утверждение в сложном типе для
allNffgsAndPolicies
:<xs:element name="allNffgsAndPolicies"> <xs:complexType> <xs:sequence> <!-- same content as in original schema --> </xs:sequence> <xs:assert test="every $i in tns:policy satisfies $i/@srcNode = tns:nffg/tns:nodes/tns:node/@nodeName and $i/@destNode = tns:nffg/tns:nodes/tns:node/@nodeName"/> </xs:complexType> <!-- other keys and keyRefs, only keep the first three --> </xs:element>
Я мог бы успешно проверить это в oXygen: он проверяет исходный документ и не проходит проверку при использовании несуществующих имен источника или узла назначения.
Чтобы активировать XML-схему 1.1, добавьте эти атрибуты в xs:schema
элемент:
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"
Чтобы пройти лишнюю милю: если к тому же, вы также хотите убедиться, что имя узла существует в nffg, на который ссылается политика с nffgRef
Вы можете точно настроить утверждение:
<xs:assert test="
every $i in tns:policy satisfies
$i/@srcNode = tns:nffg[@nffgName eq $i/@nffgRef]/tns:nodes/tns:node/@nodeName
and
$i/@destNode = tns:nffg[@nffgName eq $i/@nffgRef]/tns:nodes/tns:node/@nodeName"/>