34 votes

Validation de XML avec XSD ... mais toujours permettre l'extensibilité

C'est peut-être moi, mais il semble que si vous avez un XSD

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="User">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="GivenName" />
                <xs:element name="SurName" />
            </xs:sequence>
            <xs:attribute name="ID" type="xs:unsignedByte" use="required" />
        </xs:complexType>
    </xs:element>
</xs:schema>

qui définit le schéma de ce document

<?xml version="1.0" encoding="utf-8" ?>
<User ID="1">
    <GivenName></GivenName>
    <SurName></SurName>
</User>

Il ne parviendrait pas à valider si vous avez ajouté un autre élément, dire votre Adresse de courrier électronique, et de mélanger l'ordre

<?xml version="1.0" encoding="utf-8" ?>
<User ID="1">
    <SurName></SurName>
    <EmailAddress></EmailAddress>
    <GivenName></GivenName>
</User>

Je ne veux pas d'ajouter votre Adresse de courrier électronique du document et ont marqué facultatif.

Je veux juste un XSD qui valide le strict minimum les exigences que le document doit répondre.

Est-il un moyen de faire cela?

EDIT:

marc_s souligné ci-dessous que vous pouvez utiliser xs:any à l'intérieur de l' xs:sequence afin de permettre plus d'éléments, malheureusement, vous avez à maintenir l'ordre des éléments.

Sinon, je peux utiliser xs:all ce qui ne veut pas respecter l'ordre des éléments, mais, hélas, ne m'autorise pas à la place xs:any à l'intérieur de lui.

57voto

Abel Points 24335

Votre question a une résolution, mais il ne sera pas assez. Voici pourquoi:

Violation de non-déterministe des modèles de contenu

Vous avez déjà touché à l'âme de W3C XML du Schéma. Ce que vous demandez — ordre variable et la variable d'éléments inconnus — viole la plus difficile, mais la plupart des principe de base de XSD, la règle de la Non-Ambiguïté, ou, plus formellement, l' Attribution de Particule Unique Contrainte:

Un modèle de contenu doivent être établies de telle que lors de la validation [..] chaque élément dans la séquence peut être unique déterminé, sans examiner les le contenu ou les attributs de l'élément, et sans aucune information sur les les éléments dans le reste de la la séquence.

En anglais normal: quand un fichier XML est validé et le XSD processeur de rencontres, <SurName> il doit être en mesure de valider sans vérifier d'abord si elle est suivie par l' <GivenName>, c'est à dire, pas de hâte. Dans votre scénario, ce n'est pas possible. Cette règle existe pour permettre des implémentations par des Machines à états Finis, ce qui devrait rendre les implémentations plutôt trivial et rapide.

C'est l'une des plus controversée de questions et est un héritage de SGML et de la DTD (modèles de contenu doit être déterministe) et XML, qui définit, par défaut, que l'ordre des éléments est important (ainsi, en essayant le contraire, la commande sans importance, est dur).

Comme Marc_s déjà suggéré, Relax_NG est une alternative qui permet de modèles de contenu non déterministes. Mais que pouvez-vous faire si vous êtes coincé avec des schémas XML du W3C?

Non-travail semi-valides solutions

Vous avez déjà remarqué qu' xs:all est très restrictive. La raison en est simple: la même non-déterministe de la règle s'applique et c'est pourquoi, xs:any, min/maxOccurs de plus de l'un et de séquences ne sont pas autorisés.

Aussi, vous avez essayé toutes sortes de combinaisons d' choice, sequence et any. L'erreur que Microsoft XSD processeur déclenche lors de la rencontre d'invalide situation est la suivante:

Erreur: Plusieurs définition de l'élément 'http://example.com/Chad:SurName' causes le modèle de contenu de devenir ambigu. Un modèle de contenu doit être formés tels que lors de la validation de un élément d'information d'élément de la séquence, les particules contenues directement, indirectement ou implicitement, y avec pour tenter de valider chaque élément dans la séquence, à son tour, peut être déterminée de manière unique et sans examen le contenu ou les attributs de l' item, et sans aucune information sur les éléments dans le reste de la séquence.

Dans O'Reilly Schéma XML (oui, le livre a ses défauts) c'est très bien expliqué. Furtunately, les parties de l'ouvrage sont disponibles en ligne. Je vous recommande fortement de lire à travers la section 7.4.1.3 à propos de l' Attribution de Particule Unique Règle, leurs explications et des exemples sont beaucoup plus claire que je ne peux jamais obtenir.

Une solution de travail

Dans la plupart des cas, il est possible de partir d'un undeterministic d'une conception déterministe de la conception. Ce n'est généralement pas l'air joli, mais c'est une solution si vous devez coller avec le W3C XML Schema et/ou si vous devez absolument permettre à des règles strictes à votre XML. Le cauchemar avec votre situation, c'est que vous voulez appliquer une chose (2 éléments prédéfinis) et en même temps envie de l'avoir très lâche (l'ordre n'a pas d'importance et que tout peut aller entre avant et après). Si je ne cherche pas à vous donner de bons conseils, mais juste vous prendre directement à une solution, elle sera comme suit:

<xs:element name="User">
    <xs:complexType>
        <xs:sequence>
            <xs:any minOccurs="0" processContents="lax" namespace="##other" />
            <xs:choice>
                <xs:sequence>                        
                    <xs:element name="GivenName" />
                    <xs:any minOccurs="0" processContents="lax" namespace="##other" />
                    <xs:element name="SurName" />
                </xs:sequence>
                <xs:sequence>
                    <xs:element name="SurName" />
                    <xs:any minOccurs="0" processContents="lax" namespace="##other" />
                    <xs:element name="GivenName" />
                </xs:sequence>
            </xs:choice>
            <xs:any minOccurs="0" processContents="lax" namespace="##any" />
        </xs:sequence>
        <xs:attribute name="ID" type="xs:unsignedByte" use="required" />
    </xs:complexType>
</xs:element>

Le code ci-dessus fait fonctionne, tout simplement. Mais il y a quelques mises en garde. La première est xs:any avec ##other que son espace de noms. Vous ne pouvez pas utiliser ##any, à l'exception de la dernière, parce que cela permettrait à des éléments comme l' GivenName à l'être en place et qui signifie que la définition de l' User devient ambigu.

Le deuxième inconvénient est que si vous voulez utiliser cette astuce avec plus de deux ou trois, vous aurez à écrire toutes les combinaisons. Un entretien cauchemar. C'est pourquoi je viens avec les éléments suivants:

La solution proposée, une variante d'un Contenu Variable Contenant

Changer votre définition. Cela a l'avantage d'être plus clair à vos lecteurs ou utilisateurs. Il a également l'avantage d'être plus facile à maintenir. Toute une série de solutions sont expliquées sur XFront ici, un moins lisible lien que vous avez déjà vu le post de Oleg. C'est une excellente lecture, mais la plupart ne prennent pas en compte le fait que vous avez un minimum de deux éléments à l'intérieur de la variable contenu du conteneur.

L'actuel meilleur approche pratique pour votre situation (ce qui arrive plus souvent que vous ne l'imaginez) est de séparer vos données entre le nécessaire et non les champs requis. Vous pouvez ajouter un élément <Required>, ou faire le contraire, l'ajout d'un élément <ExtendedInfo> (ou de l'appeler Propriétés, ou OptionalData). Ceci se fait comme suit:

<xs:element name="User2">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="GivenName" />
            <xs:element name="SurName" />
            <xs:element name="ExtendedInfo" minOccurs="0">
                <xs:complexType>
                    <xs:sequence>
                        <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax" namespace="##any" />
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>

Cela peut sembler moins que l'idéal pour le moment, mais de laisser pousser un peu. Avoir un ensemble ordonné d'éléments fixes n'est pas que les grandes d'un accord. Vous n'êtes pas le seul qui va se plaindre de cette carence apparente de W3C XML Schema, mais comme je l'ai dit plus haut, si vous avez à l'utiliser, vous devrez vivre avec ses limites, ou d'accepter le fardeau de développement autour de ces limitations à un coût plus élevé de la propriété.

Solution Alternative

Je suis sûr que vous le savez déjà, mais l'ordre des attributs par défaut est indéterminé. Si votre contenu est de types simples, vous pouvez également choisir de faire une plus grande utilisation des attributs.

Un dernier mot

Quelle que soit l'approche que vous prenez, vous perdez beaucoup de vérifiabilité de vos données. Il est souvent préférable de permettre aux fournisseurs de contenu pour ajouter des types de contenu, mais uniquement lorsqu'il peut être vérifié. Ce que vous pouvez faire en passant d' lax de strict traitement et en rendant les types eux-mêmes de plus en plus strictes. Mais être trop strict n'est pas bon, le juste équilibre dépendra de votre capacité à juger les cas d'utilisation que vous êtes contre et pesant que contre le compromis de certaines stratégies de mise en œuvre.

6voto

Oleg Points 136406

Après la lecture de la réponse de marc_s et votre discussion dans les commentaires, je décide d'ajouter un peu de.

Il me semble qu' il n'existe pas de solution parfaite à votre problème Tchad. Il y a quelques approches de la façon de mettre en œuvre extensible modèle de contenu dans XSD, mais tous me connu de mise en œuvre ont quelques restrictions. Parce que vous n'avez pas à écrire au sujet de l'environnement dans lequel vous prévoyez d'utiliser extensible XSD je peux vous recommandons seulement quelques liens qui sera probablement vous aider à choisir la voie qui peut être mis en œuvre dans votre environnement:

  1. http://www.xfront.com/ExtensibleContentModels.html (ou http://www.xfront.com/ExtensibleContentModels.pdf) et http://www.xfront.com/VariableContentContainers.html
  2. http://www.xml.com/lpt/a/993 (ou http://www.xml.com/pub/a/2002/07/03/schema_design.html)
  3. http://msdn.microsoft.com/en-us/library/ms950793.aspx

4voto

marc_s Points 321990

Vous devriez être en mesure d'étendre votre schéma avec l' <xs:any> élément pour l'extensibilité - voir W3Schools pour plus de détails.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="User">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="GivenName" />
                <xs:element name="SurName" />
                <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax" />
            </xs:sequence>
            <xs:attribute name="ID" type="xs:unsignedByte" use="required" />
        </xs:complexType>
    </xs:element>
</xs:schema>

Lorsque vous ajoutez l' processContents="lax" alors la .NET de validation XML devrait réussir sur elle.

Voir MSDN docs sur xs:tout pour plus de détails.

Mise à jour: si vous avez besoin de plus de flexibilité et moins rigoureux de validation, vous voudrez peut-être consulter d'autres méthodes de définition des schémas pour votre XML - quelque chose comme RelaxNG. XML Schema est - à dessein - plutôt stricte sur ses règles de fonctionnement, peut-être que c'est juste le mauvais outil pour ce travail à la main.

1voto

ZXX Points 3216

Eh bien, vous pouvez toujours utiliser la DTD :-) sauf que les DTD aussi prescrit de la commande. Validation avec "non ordonnée" la grammaire est terriblement cher. Vous pourriez jouer avec xsd:choice et min et max se produit, mais elle va probablement se dérober ainsi. Vous pouvez également écrire XSD extensions / dérivés de schémas.

La façon dont vous avez posé le problème, il semble que vous n'avez pas vraiment envie XSD à tous. Vous pouvez simplement charger puis valider ce que vous voulez avec Xpath, mais juste pour protester contre XSD, combien d'années après, il est devenu omni-présente norme est vraiment, vraiment ne va pas vous obtenir n'importe où.

1voto

RelaxNG permettra de résoudre ce problème de manière succincte, si vous pouvez l'utiliser. Le déterminisme n'est pas une exigence pour les schémas. Vous pouvez traduire un RNG ou RNC schéma dans XSD, mais il s'apparente dans ce cas. Si c'est assez bon pour votre utilisation est à vous.

Le RNC de schéma pour ce cas est:

start = User
User = element User {
   attribute ID { xsd:unsignedByte },
   ( element GivenName { text } &
     element SurName { text } &
     element * - (SurName | GivenName) { any })
}

any = element * { (attribute * { text } | text | any)* }

La toute règle correspond à n'importe quel XML bien formé fragment. Donc, cela demandera à l'Utilisateur de l'élément de contenir Prénom et Nom de famille d'éléments contenant du texte dans n'importe quel ordre, et de permettre à d'autres éléments contenant à peu près tout.

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