I have two lists of different elements (ruleRef
and rule
) in the same XML file.
I'd like to make sure that the content of ruleRef
equals the name of any rule
.
In my XSD I already have a xs:key
restriction like such:
<xs:key name="ruleName">
<xs:selector xpath="rules/rule"/>
<xs:field xpath="@name"/>
</xs:key>
I've also used this key before to validate the attribute of another element like such:
<xs:keyref name="differentRuleRef" refer="ruleName">
<xs:selector xpath="rules/rule/differentRuleRef"/>
<xs:field xpath="@referencedRule"/>
</xs:keyref>
Now I'd like to validate the actual content of an element instead of an attribute.
E.g. in the following XML the second <ruleRef>
element should be invalid:
<root>
<rules>
<rule name="rule1"/>
<rule name="rule2"/>
</rules>
<ruleRefs>
<ruleRef>rule1</ruleRef>
<ruleRef>nonExistantRule</ruleRef> <!-- invalid -->
</ruleRefs>
</root>
I've tried text()
and data(.)
before, but both of them are not valid in the XPath-subset.
I've also tried .
and ruleRef
, but they didn't seem to validate anything.
Using .
for the xs:field
in your xs:keyref
should be working, I rather suspect a mistatch in the XPath for the xs:selector
.
On the <root>
element, defining the following in the schema is working on the XML sample you provided:
<xs:element name="root" type="root">
<xs:key name="ruleName">
<xs:selector xpath="rules/rule"/>
<xs:field xpath="@name"/>
</xs:key>
<xs:keyref refer="ruleName" name="differentRuleRef">
<xs:selector xpath="ruleRefs/ruleRef"/>
<xs:field xpath="."/>
</xs:keyref>
</xs:element>
<xs:complexType name="root">
<!-- define root content type here ...-->
</xs:complexType>
Another approach (somewhat simpler) could be to use the ID / IDREF mechanism, and you can get rid of the xs:key
/ xs:keyref
definition in your shema, and modify the definition of rules and ruleRefs :
<xs:element name="rule" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:ID" />
</xs:complexType>
</xs:element>
<xs:element name="ruleRef" type="xs:IDREF" maxOccurs="unbounded">
</xs:element>
This will constraint the rule names to be unique.