Search code examples
phpxmlxsdprimary-keykeyref

Xml validation against xml schema fails in php but works in .NET (VS2010)


I have several xml files, but I will present only one and the xsd against which I validate it. Let me describe the problem at first. I edit the files in VS2010 and the VS run time parser shows no errors while editting the xml file. Then when I run a php command line script which loads the xml file and validates it against the xml schema, it ends with an excption saying

Warning: DOMDocument::schemaValidate(): Element 'element': No match found for key-sequence ['answers'] of keyref 'elementRef'.

However, I really cannot see a mistake in the xsd file.

Xml file:

<domain xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Answer" namespace="Custom\Surveys" xsi:noNamespaceSchemaLocation="../../xsd/domain.xsd">
    <entities>
        <entity name="Answer" main="true" schema="answers"/>
    </entities>
    <bindings>      
    </bindings>
    <key>
        <element entity="answers" property="question_option_id"/>
        <element entity="answers" property="survey_voter_id"/>
    </key>
</domain>

Xml schema in an xsd file:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">   
    <xs:element name="domain">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="entities">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="entity" minOccurs="1" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:attribute name="name" type="xs:string" use="required" id="entityName" />
                                    <xs:attribute name="main" type="xs:boolean" use="optional" default="false" />
                                    <xs:attribute name="schema" type="xs:string" use="required" id="schemaName" />                                  
                                </xs:complexType>                               
                            </xs:element>
                            <xs:element name="multientity" minOccurs="0" maxOccurs="1">
                                <xs:complexType>
                                    <xs:attribute name="name" type="xs:string" use="required" />
                                    <xs:attribute name="schema" type="xs:string" use="required" />
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>                   
                </xs:element>
                <xs:element name="bindings" minOccurs="0" maxOccurs="1">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="bind" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="referenced">
                                            <xs:complexType>
                                                <xs:attribute name="entity" type="xs:string" use="required" />
                                                <xs:attribute name="property" type="xs:string" use="required" />
                                            </xs:complexType>
                                            <xs:keyref name="referencedRef" refer="entityId">
                                                <xs:selector xpath="." />
                                                <xs:field xpath="@entity" />
                                            </xs:keyref>
                                        </xs:element>
                                    </xs:sequence>
                                    <xs:attribute name="entity" type="xs:string" use="required" />
                                    <xs:attribute name="property" type="xs:string" use="required" />
                                </xs:complexType>
                                <xs:keyref name="bindRef" refer="entityId">
                                    <xs:selector xpath="." />
                                    <xs:field xpath="@entity" />
                                </xs:keyref>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="key">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="element" minOccurs="1" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:attribute name="entity" type="xs:string" use="required" />
                                    <xs:attribute name="property" type="xs:string" use="required" />
                                </xs:complexType>
                                <xs:keyref name="elementRef" refer="entityId">
                                    <xs:selector xpath="." />
                                    <xs:field xpath="@entity" />
                                </xs:keyref>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>                   
                </xs:element>
            </xs:sequence>
            <xs:attribute name="name" type="xs:string" use="required" />            
            <xs:attribute name="namespace" type="xs:string" use="required" />
        </xs:complexType>
        <xs:key name="entityId">
            <xs:selector xpath="./entities/entity|./entities/multientity" />
            <xs:field xpath="@schema" />
        </xs:key>
    </xs:element>
</xs:schema>

Solution

  • I have found a solution, I had to define all the keys and keyrefs in the root element at the end.

    Here goes the new xsd file:

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">   
        <xs:element name="domain">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="entities">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element name="entity" minOccurs="1" maxOccurs="unbounded">
                                    <xs:complexType>
                                        <xs:attribute name="name" type="xs:string" use="required" id="entityName" />
                                        <xs:attribute name="main" type="xs:boolean" use="optional" default="false" />
                                        <xs:attribute name="schema" type="xs:string" use="required" id="schemaName" />                                  
                                    </xs:complexType>                               
                                </xs:element>
                                <xs:element name="multientity" minOccurs="0" maxOccurs="1">
                                    <xs:complexType>
                                        <xs:attribute name="name" type="xs:string" use="required" />
                                        <xs:attribute name="schema" type="xs:string" use="required" />
                                    </xs:complexType>
                                </xs:element>
                            </xs:sequence>
                        </xs:complexType>                   
                    </xs:element>
                    <xs:element name="bindings" minOccurs="0" maxOccurs="1">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element name="bind" minOccurs="0" maxOccurs="unbounded">
                                    <xs:complexType>
                                        <xs:sequence>
                                            <xs:element name="referenced">
                                                <xs:complexType>
                                                    <xs:attribute name="entity" type="xs:string" use="required" />
                                                    <xs:attribute name="property" type="xs:string" use="required" />
                                                </xs:complexType>                                           
                                            </xs:element>
                                        </xs:sequence>
                                        <xs:attribute name="entity" type="xs:string" use="required" />
                                        <xs:attribute name="property" type="xs:string" use="required" />
                                    </xs:complexType>                               
                                </xs:element>
                            </xs:sequence>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="key">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element name="element" minOccurs="1" maxOccurs="unbounded">
                                    <xs:complexType>
                                        <xs:attribute name="entity" type="xs:string" use="required" />
                                        <xs:attribute name="property" type="xs:string" use="required" />
                                    </xs:complexType>
                                </xs:element>
                            </xs:sequence>
                        </xs:complexType>                   
                    </xs:element>
                </xs:sequence>
                <xs:attribute name="name" type="xs:string" use="required" />            
                <xs:attribute name="namespace" type="xs:string" use="required" />
            </xs:complexType>
            <xs:key name="entityId">
                <xs:selector xpath="./entities/entity|./entities/multientity" />
                <xs:field xpath="@schema" />
            </xs:key>
            <xs:keyref name="elementRef" refer="entityId">
                <xs:selector xpath="./key/element" />
                <xs:field xpath="@entity" />
            </xs:keyref>
            <xs:keyref name="bindRef" refer="entityId">
                <xs:selector xpath="./bindings/bind" />
                <xs:field xpath="@entity" />
            </xs:keyref>
            <xs:keyref name="referencedRef" refer="entityId">
                <xs:selector xpath="./bindings/bind/referenced" />
                <xs:field xpath="@entity" />
            </xs:keyref>
        </xs:element>
    </xs:schema>