validación xsd basada en dos claves

Quiero validar el siguiente xml:

<?xml version="1.0" encoding="UTF-8"?>

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <root1>
        <items>
            <item id="1">
                <interfaces>
                    <interface id="0"/>
                    <interface id="1"/>
                    <interface id="2"/>
                </interfaces>
            </item>
            <item id="2">
                <interfaces>
                    <interface id="10"/>
                    <interface id="11"/>
                    <interface id="2"/>
                </interfaces>
            </item>
        </items>
        <connections>
            <connection id="1">
                <point item="1" interface="0"/>
                <point item="2" interface="10"/>
            </connection>
            <connection id="2">
                <point item="1" interface="1"/>
                <point item="2" interface="11"/>
            </connection>
            <connection id="3">
                <point item="1" interface="2"/>
                <point item="2" interface="157"/>      <-- this one is not valid as there is no interface 157 under item 2.
            </connection>
        </connections>
    </root1>
</root>

Ese es el código para validar el artículo:

<?xml version="1.0" encoding="ISO-8859-1"?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="root1" type="root1" minOccurs="1" maxOccurs="1"/>
            </xs:sequence>
        </xs:complexType>
        <xs:keyref name="endPointIntfKeyRef" refer="interfaceKey">
            <xs:selector xpath="root1/connections/connection/point"/>
            <xs:field xpath="@interface"/>
        </xs:keyref>
    </xs:element>

    <xs:complexType name="root1">
        <xs:sequence>
            <xs:element name="items" minOccurs="1" maxOccurs="1">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="item" type="item" minOccurs="1" maxOccurs="unbounded"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
            <xs:element name="connections" minOccurs="0" maxOccurs="1">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="connection" type="connection" minOccurs="1" maxOccurs="unbounded"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="item">
        <xs:sequence>
            <xs:element name="interfaces" minOccurs="0" maxOccurs="1">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="interface" type="interface" minOccurs="1" maxOccurs="unbounded"/>
                    </xs:sequence>
                </xs:complexType>
                    <xs:unique name="interfaceKey">
                        <xs:selector xpath="interface"/>
                        <xs:field xpath="@id"/>
                    </xs:unique>
            </xs:element>
        </xs:sequence>
        <xs:attribute name="id" type="xs:int" use="required"/>
    </xs:complexType>

    <xs:complexType name="interface">
        <xs:attribute name="id" type="xs:int" use="required"/>
    </xs:complexType>

    <xs:complexType name="connection">
        <xs:sequence>
            <xs:element name="point" minOccurs="2" maxOccurs="2">
                <xs:complexType>
                    <xs:attribute name="item" type="xs:int" use="required"/>
                    <xs:attribute name="interface" type="xs:int" use="required"/>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
        <xs:attribute name="id" type="xs:int" use="required"/>
    </xs:complexType>

</xs:schema>

Pero produce 'Se encontró más de una coincidencia para la secuencia de teclas' que no quiero tener ya que las interfaces son únicas en un elemento específico.

$ xmllint --noout --schema 1.xsd 1.xml 
1.xml:31: Schemas validity error : Element 'point': More than one match found for key-sequence ['2'] of keyref 'endPointIntfKeyRef'.
1.xml:32: Schemas validity error : Element 'point': No match found for key-sequence ['157'] of keyref 'endPointIntfKeyRef'.
1.xml fails to validate

¿Cómo obtener solo el segundo error 'Elemento 'punto': no ​​se encontró ninguna coincidencia para la secuencia de teclas ['157'] de keyref 'endPointIntfKeyRef' y no la primera?

preguntado el 15 de febrero de 14 a las 20:02

Este material de referencia clave era nuevo para mí. Encontré que la siguiente página es una buena explicación: zvon.org/xxl/XMLSchemaTutorial/Output/ser_keys_st5.html -

1 Respuestas

El mensaje de error es correcto - hay están dos posibles coincidencias en el interfaceKey para el valor keyref 2. Para obtener el comportamiento que necesita, necesitaría un valor de clave compuesto que incluya el item identificación, así como el interface ID que luego podría keyref usando tanto el item y interface atributos en point, pero eso significaría definir el unique restricción como

<xs:unique name="interfaceKey">
    <xs:selector xpath="interface"/>
    <xs:field xpath="../@id"/><!-- not allowed in 1.0 -->
    <xs:field xpath="@id"/>
</xs:unique>

y XML Schema 1.0 no permite .. en expresiones XPath de campo o selector (restringidas).

Respondido 15 Feb 14, 20:02

Gracias, ¿en qué versión de esquema xml es compatible? ¿Y cómo cambiar mi código para usarlo? - vitalivanov

@vitalivanov XML Schema v1.1 permite el lenguaje XPath 2.0 completo, pero no es tan ampliamente compatible como 1.0. Una alternativa podría ser investigar el uso de reglas de Schematron para expresar las restricciones que no puede hacer en el esquema básico. - Ian Roberts

Entonces, ¿este tipo de validación no es posible en el esquema 1.0? - vitalivanov

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.