1

My XML structure is the following:

ROOT
   |_ SetOfBandC (*)
   |               |_ SetOfB (1)
   |               |           |_ ElementB (*)
   |               |           |_ ElementB__Key 
   |               |_ SetOfC (1)
   |                           |_ ElementC (*)
   |                           |_ ElementC__Key 
   |_ ElementD (*)
   |
   |_ SetOfBandC__Key
   |_ ElementD__Key
   |
   |_ ElementD->SetOfBandC__Keyref
   |_ ElementD->ElementB__Keyref

In this structure I can have multiple SetOfBandC as well as multiple ElementB and ElementC, but only 1 SetofB and SetOfC for each SetOfBandC.

The problem is that ElementD has a keyref referencing a particular SetOfBandC and another one referencing a ElementB of that set, but the XML Validator when checking for the ElementD->ElementB__Keyref's validity it only searches in the last SetOfBandC, and not in all of them or, better, in the one referenced by ElementD->SetOfBandC__Keyref. So when ElementD->ElementB__Keyref references an ElementB which is not in the last SetOfBandC, validation won't work.

Here is my 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>

And my ElementB__Key:

<xs:key name="ElementB__Key">
    <xs:selector xpath="tns:ElementB" />
    <xs:field xpath="@elemB_name" />
</xs:key>

Where tns is my target namespace. What am I missing?

PS: names in my code are different and there are not -> in them.

RVKS
  • 147
  • 3
  • 16

2 Answers2

1

I think the issue is with the scope of the keys.

As far as I understand, a node is globally identified not only by its node name, but also by the name of the nffg is belongs to. This is thus globally a compound key: a policy refers to a node with an nffg name as well as a node name. In the current schema, the keyRefs in policies however only refer to these two keys independently from each other, so XML Schema doesn't know that they go together.

Maybe a way out would be to use globally unique node names made of prefixing the node key with the nffg key, like Nffg1-Node1, and to use this instead as a single keyref in the policy. If you also want to make sure that a link refers to a source and destination node within the same nffg, you may need two key definitions for node: one global for the policy keyRefs (under allNffgsAndPolicies), one local to an nffg (under nffg) for the link keyRefs.

A slightly different alternative is to repeat the nffgName attribute in nodes, and use this together with the unchanged nodeName attribute as a global compound key for nodes -- by using two xs:field elements in the key -- that you can use in policies. You should be able to ensure that a node's local nffgname attribute matches that of the parent nffg with keys and keyRefs as well.

Bonus question: it still does not explain why, with the original instance and schema, Node3 is rejected but other values are accepted. I would have expected the error to be thrown on a value present on both subtrees. In the specification, conflicting keys across children are removed from the node table, however in this case a key like Node2 would be conflicting as it is on both subtrees, but not Node3 as it only appears in the first subtree. The contrary happens here though and only the last child's node table seems to be considered for inclusion in the top-level node table.

Ghislain Fourny
  • 6,971
  • 1
  • 30
  • 37
  • Thanks for the nice ideas. Sadly I can't modify much of the schema since it is already used by xml files and even by some applications, it would be better to modify just the key/keyrefs in order to make the problematic ones, `srcNodeRef` and `destNodeRef`, work. – RVKS Jan 18 '17 at 13:47
  • Thank you for the feedback, RVKS. I have posted another answer that should fulfil this additional constraint. – Ghislain Fourny Jan 18 '17 at 15:37
1

If you are able to use XML Schema 1.1, the following should work with no modification of XML documents or of the schema structure itself.

  • Remove both keyRefs for tns:policy

  • Instead, use an assertion in the complex type for 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>
    

I could test this successfully in oXygen: it validates the original document, and fails validation if using unexisting source or destination node names.

To activate XML Schema 1.1, add these attributes in the xs:schema element:

xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"

To go the extra mile: if on top of that, you also want to make sure that the node name exists within the nffg referenced by the policy with nffgRef, you can fine-tune the assertion:

<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"/>
Ghislain Fourny
  • 6,971
  • 1
  • 30
  • 37
  • Sadly I cannot use XML Schema 1.1. But thank you again for your great support! Do you think that there is no way of doing that with `keyref`s? Even your first solution, the one which searches for the node in all the Nffgs and not in the pointed one, would be ok. – RVKS Jan 18 '17 at 18:43