Michael J
Michael J

Reputation: 2545

Confusion over error message "invalid XPath for selector or field"

I am trying to better understand key and keyref and how to use them in a schema. I would like to apply a key to parts of type y, but not parts of type z. I am confused as to why I am seeing the following error.

'r:B/r:part[@type='y']' is an invalid XPath for selector or field

I am all but certain that the XPath is valid, but I get an error from Visual Studio as soon as I enter the predicate filter in the XPath expression.

Here is the XML

<root xmlns="namespace1">
  <A>
    <!-- if the ref-number is not equal to one of the key-number, the validation will give error -->
    <part ref-number="1"/>
  </A>
  <A>
    <!-- if the ref-number is not equal to one of the key-number, the validation will give error -->
    <part ref-number="2"/>
  </A>
  <B>
    <part type="y" key-number="1"/>
    <part type="y" key-number="2"/>
    <part type="z" key-number="3"/>
  </B>
</root>

Here is the schema

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="namespace1" xmlns:r="namespace1" elementFormDefault="qualified">
      <xs:element name="root">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="A" type="r:aType" maxOccurs="unbounded">
              <xs:keyref name="dummy" refer="r:partNumberKey">
                <xs:selector xpath="r:part"/>
                <xs:field xpath="@ref-number"/>
              </xs:keyref>
            </xs:element>
            <xs:element name="B" type="r:bType"/>
          </xs:sequence>
        </xs:complexType>
        <xs:key name="partNumberKey">
<!-- I get an error here -->
          <xs:selector xpath="r:B/r:part[@type='y']"/>
          <xs:field xpath="@key-number"/>
        </xs:key>
      </xs:element>
      <xs:complexType name="aType">
        <xs:sequence>
          <xs:element name="part" maxOccurs="unbounded">
            <xs:complexType>
              <xs:simpleContent>
                <xs:extension base="xs:string">
                  <xs:attribute name="ref-number" type="xs:integer"/>
                </xs:extension>
              </xs:simpleContent>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="bType">
        <xs:sequence>
          <xs:element name="part" maxOccurs="unbounded">
            <xs:complexType>
              <xs:simpleContent>
                <xs:extension base="xs:string">
                  <xs:attribute name="key-number" type="xs:integer"/>
                  <xs:attribute name="type" type="xs:string"/>
                </xs:extension>
              </xs:simpleContent>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    </xs:schema>

Upvotes: 2

Views: 1840

Answers (1)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22617

You get a more meaningful error message from Xerces/Oxygen:

[Xerces] c-general-xpath: The expression 'r:B/r:part[@type='y']' is not valid with respect to the XPath subset supported by XML Schema.

XML Schema only supports a subset of XPath. The following rule lists the contents allowed as the value of the xpath attribute of xs:selector:

[1]     Selector       ::=      Path ( '|' Path )*
[2]     Path       ::=      ('.//')? Step ( '/' Step )*
[3]     Step       ::=      '.' | NameTest
[4]     NameTest       ::=      QName | '*' | NCName ':' '*'

Which is a cryptic way of saying that expressions with predicates (between [ and ]) are not supported in this context.

If you have designed this XML yourself, you could give distinct names to part elements instead of different type attributes.


Another approach would be to include a Schematron rule in your XML Schema that performs this check.

Modified XML Schema with embedded Schematron

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:r="namespace1"
    xmlns:sch="http://purl.oclc.org/dsdl/schematron"
    targetNamespace="namespace1"
    elementFormDefault="qualified">

    <xs:annotation>
        <xs:appinfo>
            <sch:ns uri="namespace1"
                prefix="r" />
            <sch:pattern>
                <sch:rule context="r:A/r:part">
                    <sch:assert test="@ref-number = /r:root/r:B/r:part/@key-number">Key Error!</sch:assert>
                </sch:rule>
            </sch:pattern>
        </xs:appinfo>
    </xs:annotation>

    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="A" type="r:aType" maxOccurs="unbounded"/>
                <xs:element name="B" type="r:bType"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="aType">
        <xs:sequence>
            <xs:element name="part" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:string">
                            <xs:attribute name="ref-number" type="xs:integer"/>
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="bType">
        <xs:sequence>
            <xs:element name="part" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:string">
                            <xs:attribute name="key-number" type="xs:integer"/>
                            <xs:attribute name="type" type="xs:string"/>
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

I am not sure this is exactly what you want, because I did not fully understand why the type attribute of the part elements matters.

If you reference the XSD in your XML instance document, you now also need to include a reference for the Schematron rule, along the lines of

<?xml-model href="../Desktop/key.xsd" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>

Upvotes: 4

Related Questions