Схема 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"/>
Другие вопросы по тегам