Reputation: 157
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.
Upvotes: 1
Views: 385
Reputation: 7279
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 keyRef
s 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"/>
Upvotes: 1
Reputation: 7279
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 keyRef
s 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 keyRef
s (under allNffgsAndPolicies
), one local to an nffg (under nffg
) for the link keyRef
s.
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 key
s and keyRef
s 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.
Upvotes: 1