11 votes

Contrainte XSD unique sur l'attribut d'éléments frères d'un type spécifique

J'ai un document XML structuré sous forme de questions-réponses qui suit le format suivant (édité pour plus de clarté) :

<question>
    <answer id="1">
        <question>
            <answer id="1"/>
            <answer id="2"/>
            <answer id="3"/>
        </question>
    </answer>
    <answer id="2">
        <question>
            <answer id="1"/>
            <answer id="2"/>
        </question>
    </answer>
</question>

Mon XSD ressemble à ceci :

<xs:element name="question">
     <xs:complexType>
        <xs:sequence>
            <xs:element name="answer" type="answerType" minOccurs="2" maxOccurs="unbounded">
            </xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:unique name="AnswerIdUnique">
        <xs:selector xpath="./*" />
        <xs:field xpath="@id" />
    </xs:unique>
</xs:element>

<xs:complexType name="answerType">
    <xs:sequence>
        <xs:element ref="question" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
    <xs:attribute name="id" type="xs:token" use="required" />
</xs:complexType>

Il y a bien sûr plus que ce que vous voyez ci-dessus, mais cela illustre mon problème. J'ai besoin pour le id sur l'attribut answer pour qu'ils soient uniques parmi les frères et sœurs. Le XSD défini ci-dessus impose l'unicité de l'élément id parmi les éléments frères, mais il ne fait pas de distinction en fonction du type d'élément. J'ai essayé une variété de sélecteurs et de champs dans la contrainte unique, mais je n'ai pas trouvé de combinaison qui fonctionne. Des suggestions ?

15voto

Petru Gardea Points 13264

Il suffit de changer le sélecteur en <xs:selector xpath="answer"/> et tout ira bien. En général, il est préférable d'éviter les XPaths du type .//* ne serait-ce que pour des raisons de performance.

Voici le schéma XML pour l'échantillon XML que vous avez fourni et qui, je pense, fonctionne comme vous le souhaitez :

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="question" type="questionType">
        <xs:unique name="AnswerIdUnique">
            <xs:selector xpath="answer"/>
            <xs:field xpath="@id"/>
        </xs:unique>
    </xs:element>
    <xs:complexType name="questionType">
        <xs:sequence>
            <xs:element name="answer" type="answerType" minOccurs="2" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="answerType">
        <xs:sequence>
            <xs:element ref="question" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
        <xs:attribute name="id" type="xs:token" use="required"/>
    </xs:complexType>
</xs:schema>

Le XML que vous avez posté se valide correctement avec ce qui précède ; la duplication de l'identifiant d'une réponse sœur entraîne une erreur de validation. Par exemple, le XML suivant :

<question> 
    <answer id="1"> 
        <question> 
            <answer id="1"/> 
            <answer id="2"/> 
            <answer id="1"/> 
        </question> 
    </answer> 
    <answer id="1"> 
        <question> 
            <answer id="1"/> 
            <answer id="2"/> 
        </question> 
    </answer> 
</question> 

Après validation (dans QTAssistant, le message devrait être similaire à celui de Visual Studio puisqu'il est basé sur la même technologie), voici les erreurs :

Error occurred while loading [], line 6 position 5
There is a duplicate key sequence '1' for the 'AnswerIdUnique' key or unique identity constraint.
Error occurred while loading [], line 9 position 3
There is a duplicate key sequence '1' for the 'AnswerIdUnique' key or unique identity constraint.
Document1.xml is invalid.

Vous trouverez ci-dessous une capture d'écran de Visual Studio 2010 montrant la validation XML ci-dessus par rapport au XSD que j'ai posté ; bien que les problèmes soient signalés par inadvertance en tant qu'avertissements, ils sont néanmoins signalés.

VS2010 showing unique constraint errors

J'ai choisi au hasard un validateur en ligne ( http://xsdvalidation.utilities-online.info/ ) et a validé le même XML et XSD que j'ai posté ; l'erreur est signalée comme suit :

org.xml.sax.SAXParseException: Duplicate unique value [1] declared for identity constraint of element "question".org.xml.sax.SAXParseException: Duplicate unique value [1] declared for identity constraint of element "question".

Une chose à laquelle vous devez faire attention est lorsque vous avez un espace de noms cible pour votre XSD ; dans ce cas, il est nécessaire de définir un alias pour tous les espaces de noms impliqués, et de les utiliser dans vos sélecteurs.

MISE À JOUR : Et le XSD avec les espaces de noms :

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://localhost" xmlns="http://localhost" targetNamespace="http://localhost" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="question" type="questionType">
        <xs:unique name="AnswerIdUnique">
            <xs:selector xpath="tns:answer"/>
            <xs:field xpath="@id"/>
        </xs:unique>
    </xs:element>
    <xs:complexType name="questionType">
        <xs:sequence>
            <xs:element name="answer" type="answerType" minOccurs="2" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="answerType">
        <xs:sequence>
            <xs:element ref="question" minOccurs="0" maxOccurs="1"/>
        </xs:sequence>
        <xs:attribute name="id" type="xs:token" use="required"/>
    </xs:complexType>
</xs:schema>

Veuillez noter l'introduction de la tns et son utilisation dans le sélecteur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X