Search code examples
xmlxsdxsd-validationxml-validation

XML Schema restriction defined by document being validated


Is there a way for an XML schema to define something like the following where the codes used in <item> elements are defined by the document author in the <validCodes> element. These codes themselves may be restricted to an enumeration or a simple regex match but that's not important here.

<validCodes>
  <code>AA</code>
  <code>BB</code>
</validCodes>
...
<item code="AA"> VALID </item>
<item code="BB"> VALID </item>
<item code="AB"> INVALID </item>

To rephrase this, I want to allow authors of a configuration file to define their own restrictions in XML without having to define it in terms of a schema.


Solution

  • XSD 1.0

    Your constraint cannot be expressed.

    XSD 1.1

    Your constraint can be expressed via an assertion:

    <xs:assert test="every $c in item/@code satisfies $c = validCodes/code"/>
    

    XML

    <?xml version="1.0" encoding="UTF-8"?>
    <r>
      <validCodes>
        <code>AA</code>
        <code>BB</code>
      </validCodes>
      <item code="AA"> VALID </item>
      <item code="BB"> VALID </item>
      <item code="AB"> INVALID </item>
    </r>
    

    XSD

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
               elementFormDefault="qualified"
               vc:minVersion="1.1">
      <xs:element name="r">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="validCodes">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="code" type="xs:string" maxOccurs="unbounded"/>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
            <xs:element name="item" maxOccurs="unbounded">
              <xs:complexType>
                <xs:simpleContent>
                  <xs:extension base="xs:string">
                    <xs:attribute name="code" type="xs:string"/>
                  </xs:extension>
                </xs:simpleContent>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
         <xs:assert test="every $c in item/@code satisfies $c = validCodes/code"/>
        </xs:complexType>
      </xs:element>
    </xs:schema>