Les schémas xml et la validation en .net

Les schémas xml et la validation en .net

Notion de schéma XML

De nos jours, le format XML est de plus en plus utilisé que ce soit pour le stockage de paramètres ou de données ou encore pour les WebService.

Un document XML peut être définit par un schéma qui contraint sa structure, tout comme une base de données. Cela permet d'assurer qu'un fichier XML contient des données structurées qui sont valides et que tout programme connaissant le schéma saura le lire.

Il existe plusieurs moyens de définir un schéma :

Une DTD (Document Type Definition)

C'est un document permettant de décrire un modèle de document. Il est utilisé pour tous les dérivés du SGML, comme HTML, XHTML ou XML
Il permet de définir les éléments et leurs attributs ainsi que leur séquencement.
Il définit aussi des entités qui représentent des caractères comme le é qui représente le caractère « é ».
Par contre, une DTD ne permet pas de définir une contrainte sur le contenu d'un attribut ou d'un noeud texte. Il n'est donc pas possible de dire qu'un élément ne doit contenir qu'un entier.

Définition de la DTD newspaper.dtd :

<!-- NEWSPAPER est l'élément racine -->
<!-- un NEWSPAPER contient un à plusieurs ARTICLE -->
<!ELEMENT NEWSPAPER (ARTICLE+)>
<!-- un ARTICLE contient un HEADLINE puis un BYLINE...
obligatoirement dans cet ordre -->
<!ELEMENT ARTICLE (HEADLINE,BYLINE,LEAD)>
<!-- un HEADLINE contient des données textuelles parsables -->
<!ELEMENT HEADLINE (#PCDATA)>
<!ELEMENT BYLINE (#PCDATA)>
<!ELEMENT LEAD (#PCDATA)>

<!-- un ARTICLE contient un attribut AUTHOR qui est obligatoire -->
<!ATTLIST ARTICLE AUTHOR CDATA #REQUIRED>
<!-- un ARTICLE contient un attribut EDITOR qui est facultatif -->
<!ATTLIST ARTICLE EDITOR CDATA #IMPLIED>
<!ATTLIST ARTICLE DATE CDATA #IMPLIED>
<!ATTLIST ARTICLE EDITION CDATA #IMPLIED>

<!-- &NEWSPAPER; sera remplacé par « Vervet Logic Times » -->
<!ENTITY NEWSPAPER "Vervet Logic Times">
<!ENTITY PUBLISHER "Vervet Logic Press">
<!ENTITY COPYRIGHT "Copyright 1998 Vervet Logic Press">

Fichier XML d'exemple :

<?xml version="1.0"?>
<!DOCTYPE newspaper SYSTEM "newspaper.dtd">
<NEWSPAPER>
<ARTICLE AUTHOR="ShareVB" DATE="1975-03-25">
<HEADLINE>&NEWSPAPER; for 25/03/1975</HEADLINE>
<BYLINE>ShareVB</BYLINE>
<LEAD>Lead</LEAD>
</ARTICLE>
</NEWSPAPER>

Pour plus d'informations, voir http://www.w3schools.com/xml/xml_dtd_intro.asp ou http://www.whoishostingthis.com/resources/dtd/

Un XSD (XML Schema Definition)

C'est un document permettant de définir la structure d'un document XML. A la différence d'une DTD, un schéma XSD :

  • est lui-même un XML dont le schéma s'auto-décrit.
  • permet de spécifier des contraintes sur le contenu textuel des éléments et des attributs, comme par exemple, n'autoriser que les entiers positifs ou bien forcer les doubles espaces à n'être pris en compte que comme un simple espace.

Définition du schéma XSD newspaper.xsd :

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="[http://www.w3.org/2001/XMLSchema]"
elementFormDefault="qualified">
<xs:import namespace="[http://www.w3.org/XML/1998/namespace]"/>

<!-- NEWSPAPER est l'élément racine -->
<!-- un NEWSPAPER contient un à plusieurs ARTICLE -->
<xs:complexType name="NEWSPAPER">
    <xs:sequence>
     <xs:element ref="ARTICLE" minOccurs="1" maxOccurs="unbounded"/>
    </xs:sequence>
</xs:complexType>
<xs:element name="NEWSPAPER" type="NEWSPAPER" />

<xs:complexType name="ARTICLE">
    <!-- un ARTICLE contient un HEADLINE puis un BYLINE...
obligatoirement dans cet ordre -->
    <xs:sequence>
    <!-- un HEADLINE contient des données textuelles parsables -->
     <xs:element name="HEADLINE" type="xs:string"/>
     <xs:element name="BYLINE" type="xs:string"/>
     <xs:element name="LEAD" type="xs:string"/>
    </xs:sequence>
    <!-- un ARTICLE contient un attribut AUTHOR qui est obligatoire -->
    <xs:attribute name="AUTHOR" type="xs:string" use="required"/>
     <!-- un ARTICLE contient un attribut EDITOR qui est facultatif -->
     <xs:attribute name="EDITOR" type="xs:string"/>
     <xs:attribute name="DATE" type="xs:date"/>
     <xs:attribute name="EDITION" type="xs:string"/>
</xs:complexType>
<xs:element name="ARTICLE" type="ARTICLE" />
</xs:schema>

Fichier XML d'exemple :

<?xml version="1.0" encoding="UTF-8"?>
<NEWSPAPER xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance]"
xsi:noNamespaceSchemaLocation="newspaper.xsd">
<ARTICLE AUTHOR="ShareVB" DATE="1975-03-25">
<HEADLINE>RDA for 25/03/1975</HEADLINE>
<BYLINE>ShareVB</BYLINE>
<LEAD>Lead</LEAD>
</ARTICLE>
</NEWSPAPER>

Pour plus d'informations, voir http://www.w3.org/XML/Schema.

RELAX NG

RELAX NG est un format dérivé de RELAX et TREX et approuvé par OASIS.

Définition du schéma RELAX NG :

<?xml version="1.0" encoding="UTF-8"?>
<rng:grammar xmlns:rng="[http://relaxng.org/ns/structure/1.0]" ns=""
datatypeLibrary="[http://www.w3.org/2001/XMLSchema-datatypes]">

<!-- NEWSPAPER est l'élément racine -->
<!-- un NEWSPAPER contient un à plusieurs ARTICLE -->
<rng:define name="NEWSPAPER" />
<rng:start>
<rng:ref name="NEWSPAPER"/>
</rng:start>
<rng:define name="NEWSPAPER">
<rng:element name="NEWSPAPER">
<rng:ref name="NEWSPAPER"/>
</rng:element>
</rng:define>

<rng:define name="ARTICLE">
<!-- un ARTICLE contient un HEADLINE puis un BYLINE...
obligatoirement dans cet ordre -->

<!-- un HEADLINE contient des données textuelles parsables -->
<rng:element name="HEADLINE">
<rng:data type="string"/>
</rng:element>
<rng:element name="BYLINE">
<rng:data type="string"/>
</rng:element>
<rng:element name="LEAD">
<rng:data type="string"/>
</rng:element>

<!-- un ARTICLE contient un attribut AUTHOR qui est obligatoire -->
<rng:attribute name="AUTHOR">
<rng:data type="string"/>
</rng:attribute>

<!-- un ARTICLE contient un attribut EDITOR qui est facultatif -->
<rng:attribute name="EDITOR">
<rng:data type="string"/>
</rng:attribute>
<rng:attribute name="DATE">
<rng:data type="date"/>
</rng:attribute>
<rng:attribute name="EDITION">
<rng:data type="string"/>
</rng:attribute>
</rng:define>
<rng:start>
<rng:ref name="ARTICLE"/>
</rng:start>
<rng:define name="ARTICLE">
<rng:oneOrMore>
<rng:element name="ARTICLE">
<rng:ref name="ARTICLE"/>
</rng:element>
</rng:oneOrMore>
</rng:define>
</rng:grammar>

Fichier XML d'exemple :

<?xml version="1.0" encoding="UTF-8"?>
<NEWSPAPER xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance]">
<ARTICLE AUTHOR="ShareVB" DATE="1975-03-25">
<HEADLINE>RDA for 25/03/1975</HEADLINE>
<BYLINE>ShareVB</BYLINE>
<LEAD>Lead</LEAD>
</ARTICLE>
</NEWSPAPER>

Pour plus d'nformations, voir http://relaxng.org/.

XDR (XML-Data Reduced)

C'est un format antérieur à XSD dont Microsoft est l'un des principaux implémenteurs par le biais de MSXML :

Définition du schéma XDR :

<Schema xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes">

<!-- NEWSPAPER est l'élément racine -->
<!-- un NEWSPAPER contient un à plusieurs ARTICLE -->
<ElementType name="NEWSPAPER" content="eltOnly" order="seq">
<element type="ARTICLE" minOccurs="1" maxOccurs="*" />
</ElementType>

<!-- définition des types pour les éléments -->
<ElementType name="HEADLINE" >
<datatype dt:type="string" />
</ElementType>
<ElementType name="BYLINE" >
<datatype dt:type="string" />
</ElementType>
<ElementType name="LEAD" >
<datatype dt:type="string" />
</ElementType>
<ElementType name="ARTICLE" content="eltOnly">

<!-- un ARTICLE contient un HEADLINE puis un BYLINE...
obligatoirement dans cet ordre -->
<!-- un HEADLINE contient des données textuelles parsables -->
<group order="seq">
<element type="HEADLINE" />
<element type="BYLINE"/>
<element type="LEAD"/>
</group>

<!-- un ARTICLE contient un attribut AUTHOR qui est obligatoire -->
<attribute type="AUTHOR" required="yes" />

<!-- un ARTICLE contient un attribut EDITOR qui est facultatif -->
<attribute type="EDITOR" required="no" />
<attribute type="DATE" required="no" />
<attribute type="EDITION" required="no" />

<!-- définition des types pour les attributs -->
<AttributeType name="AUTHOR" dt:type="string" />
<AttributeType name="EDITOR" dt:type="string" />
<AttributeType name="DATE" dt:type="string" />
<AttributeType name="EDITION" dt:type="string" />
</ElementType>
</Schema>

Fichier XML d'exemple :

<?xml version="1.0" encoding="utf-8"?>
<NEWSPAPER xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance]"
xmlns='x-schema:newspaper.xdr'>
<ARTICLE AUTHOR="ShareVB" DATE="1975-03-25">
<HEADLINE>RDA for 25/03/1975</HEADLINE>
<BYLINE>ShareVB</BYLINE>
<LEAD>Lead</LEAD>
</ARTICLE>
</NEWSPAPER>

Pour plus d'informations, voir http://msdn.microsoft.com/en-us/library/ms256208(VS.85).aspx.

Validation d'un fichier XML en .Net

Méthode pour le framework 1.0 et 1.1

Dans les versions 1.0 et 1.1 du framework .Net, il existait une classe spécialisée dans la validation de documents XML : XmlValidatingReader. Elle permettait de valider un document XML suivant un schéma XSD, XDR ou une DTD. Cette classe est maintenant obsolète.

//montre l'utilisation du XmlValidatingReader pour valider une DTD
//en .Net 1.1

public static void ValidateDTD_XmlValidatingReader()
{
    //le fichier XML à valider
    XmlTextReader xtr = new XmlTextReader("Articles_DTD.xml");

    //le validateur construit à partir du fichier XML
    XmlValidatingReader xvr = new XmlValidatingReader(xtr);

    //validation de DTD inline ou référencé par un DOCTYPE
    xvr.ValidationType = ValidationType.DTD;

    //méthode qui sera appelée à chaque erreur de validation
    xvr.ValidationEventHandler +=
    new ValidationEventHandler(XmlValidatingReaderHandler);

    //on lit l'ensemble du document pour le valider
    while (xvr.Read()) ;
    Console.WriteLine("Validation terminée");
}

//handler des erreurs de validation
public static void XmlValidatingReaderHandler(
object sender, ValidationEventArgs args)
{
    Console.WriteLine("Erreur de validation");
    Console.WriteLine("\tSévérité: {0}", args.Severity);
    Console.WriteLine("\tMessage: {0}", args.Message);
}

Si le fichier Articles.xml contient le contenu suivant (les erreurs sont signalées en commentaire) :

<?xml version="1.0" encoding="utf-8"?>
<!-- Fichier XML avec une DTD externe attachée -->
<!-- référencé par DOCTYPE SYSTEM -->
<!DOCTYPE article SYSTEM "articles.dtd">
<article>
    <header author="John Cartner" date="2008-09-25">
        <!--<headline>Modeling using UML</headline>-->            <!--Erreur-->
        <byline>John Cartner</byline>
        <lead>Make better program using UML modeling</lead>
        <page_count>5</page_count>
    </header>
    <add_element />            <!--Erreur-->
    <content>...</content>
    <attachment type="url">[http://msdn.microsoft.com/</attachment>]
    <attachment type="zip">...</attachment>
</article>

Et le fichier DTD :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Elément racine du document : article -->
<!-- Eléments enfants obligatoires : header et content -->
<!-- Elément enfant de 0 à plusieurs : attachement -->
<!ELEMENT article (header, content, attachment*)>

<!-- Elément facultatif : byline, lead, page_count -->
<!ELEMENT header (headline, byline?, lead?, page_count?)>

<!-- Attributs facultatifs : author et date -->
<!ATTLIST header
    author CDATA #IMPLIED
    date NMTOKEN #IMPLIED
>
<!ELEMENT headline (#PCDATA)>
<!ELEMENT byline (#PCDATA)>
<!ELEMENT lead (#PCDATA)>
<!ELEMENT page_count (#PCDATA)>
<!ELEMENT content (#PCDATA)>
<!ELEMENT attachment (#PCDATA)>

<!-- l'attribut type de l'élément attachment est
une énumération (url, zip) -->
<!ATTLIST attachment
    type (url | zip) #IMPLIED
>

Le code précédent produit les sorties suivantes :
Erreur de validation - Sévérité: Error
Message: The element 'header' has invalid child element 'byline'. List of possible elements expected: 'headline'.

Erreur de validation - Sévérité: Error
Message: The element 'article' has invalid child element 'add_element'. List of possible elements expected: 'content'.

Erreur de validation - Sévérité: Error
Message: The 'add_element' element is not declared.

Validation terminée

Méthode pour le framework 2.0 et plus

Dans le framework 2.0 et supérieurs, la validation de document XML passe par les options XmlReaderSettings de la classe XmlReader et de son implémentation XmlTextReader. Une fois les options de validation XML définies, il est nécessaire de parcourir l'ensemble du fichier XML avec la méthode Read

 //validation d'un fichier XML par un schéma XSD
public static void ValidateXSD_XmlReader()
{
    //paramètres de validation pour le reader XML
    XmlReaderSettings settings = new XmlReaderSettings();
    //validation avec schéma XSD
    settings.ValidationType = ValidationType.Schema;

    //autorise les schémas XSD internes et les schéma XSD externes
    //rapporte aussi des warnings de validation
    settings.ValidationFlags =
    XmlSchemaValidationFlags.ProcessInlineSchema

    | XmlSchemaValidationFlags.ProcessSchemaLocation

    | XmlSchemaValidationFlags.ReportValidationWarnings;

    //handler de reporting des erreurs de validation
    settings.ValidationEventHandler +=
    new ValidationEventHandler(XmlReader_Validation_Handler);

    //crée un reader avec les paramètres de validation
    XmlReader xr = XmlReader.Create(
    "Xml\\Samples\\Articles_XSD.xml", settings);

    //lit l'ensemble du document pour le valider
    while (xr.Read()) ;
    Console.WriteLine("Validation terminée");
}

//handler des erreurs de validation
static void XmlReader_Validation_Handler(
object sender, ValidationEventArgs e)
{
    Console.WriteLine("Erreur de validation");
    Console.WriteLine("\tSévérité: {0}", e.Severity);
    Console.WriteLine("\tMessage: {0}", e.Message);
}

Si le fichier Articles_XSD.xml contient le document XML suivant (les erreurs sont signalées en commentaire) :

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

<!-- Fichier XML avec un schéma XSD externe

pour l'espace de nom par défaut

référencé par xsi:noNamespaceSchemaLocation -->

<article xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance]"
xsi:noNamespaceSchemaLocation="articles.xsd">
<header author="John Cartner" date="2008-09-25">
    <headline>Modeling using UML</headline>
    <byline>John Cartner</byline>
    <lead>Make better program using UML modeling</lead>
    <!--<page_count>5</page_count>-->            <!--Erreur-->
</header>
<content>...</content>
<attachment type="url">[http://msdn.microsoft.com/</attachment>]
<attachment type="zip">...</attachment>
<add_element />            <!--Erreur-->
</article>

Et que le schéma XSD est le suivant :

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="[http://www.w3.org/2001/XMLSchema]" id="ArticlesXSD">

<!-- Elément racine du document -->
<xs:element name="article">
    <!-- définition du type article directement
    dans la définition de l'élément -->
    <xs:complexType>
        <xs:sequence>
            <!-- Elément enfant header obligatoire -->
            <xs:element name="header">
                <xs:complexType>
                    <xs:sequence>
                        <!-- qui doit contenir les éléments suivantes : -->
                        <xs:element name="headline" type="xs:string"/>
                        <!-- éléments facultatifs -->
                        <xs:element name="byline" type="xs:string" minOccurs="0"/>
                        <xs:element name="lead" type="xs:string" minOccurs="0"/>
                        <xs:element name="page_count" type="xs:int" minOccurs="1" />
                    </xs:sequence>
                    <!-- Attributs de l'élément header -->
                    <xs:attribute name="author" type="xs:string"/>
                    <xs:attribute name="date" type="xs:date"/>
                </xs:complexType>
            </xs:element>
            <!-- Element content obligatoire -->
            <xs:element name="content" type="xs:string"/>
            <!-- un ou plusieurs attachements -->
            <xs:element name="attachment" nillable="true"
            minOccurs="0" maxOccurs="unbounded">
                <xs:complexType>
                    <xs:simpleContent>
                        <xs:extension base="xs:string">
                            <!-- l'attribut type de l'élément attachment
                            est une énumération (url, zip) -->
                            <xs:attribute name="type">
                                <xs:simpleType id="attachment_types">
                                    <xs:restriction base="xs:string">
                                        <xs:enumeration value="url"/>
                                        <xs:enumeration value="zip"/>
                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:attribute>
                        </xs:extension>
                    </xs:simpleContent>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>
</xs:schema>

Le code précédent produira les erreurs de validation suivantes :

Erreur de validation - Sévérité: Error
Message: The element 'header' has incomplete content. List of possible elements expected: 'page_count'.

Erreur de validation - Sévérité: Error
Message: The element 'article' has invalid child element 'add_element'. List of possible elements expected: 'attachment'.

Validation terminée

Options de validation

Par défaut, le XmlReader effectue une normalisation des retours à la ligne, développe les entités et ajoute des attributs par défaut.

Il est possible de contrôler les options de validation par les propriétés de XmlReaderSettings :

  • CheckCharacters : indique au XmlReader de valider chaque caractère pour s'assurer qu'il est dans la plage de valeur des caractères XML et que les noms des éléments sont valides. Par défaut, tous les caractères sont validés. Néanmoins, même lorsque l'on désactive la validation des caractères, les noeuds textes sont toujours validés. Si un caractère invalide est trouvé, une exception XmlException est levée.
  • ConformanceLevel : permet d'indiquer le type de données XML à valider.
  • Auto : le XmlReader essaie de détecter le type automatiquement.
  • Fragment : indique que les données XML sont un fragment XML (pouvant contenir un noeud texte au niveau racine, plusieurs éléments au niveau racine).
  • Document : indique que les données XML sont un document XML (ne pouvant contenir qu'un élément racine à part la déclaration XML, le commentaire, des espaces blancs)
//lit un fragment XML avec un XmlReader
public static void ReadXmlFragment_XmlReader()
{
    //paramètres de lecture du fragment XML
    XmlReaderSettings settings = new XmlReaderSettings();

    //lit un fragment XML (qui peut avoir
    //plusieurs élements racines)
    settings.ConformanceLevel = ConformanceLevel.Fragment;

    //crée un reader avec les paramètres de lecture
    XmlReader xr = XmlReader.Create(
    new System.IO.StringReader(
    "<element1 att="value">texte</element1><elt2/>"),
    settings);

    //lit l'ensemble du document pour le valider
    while (xr.Read())
    Console.WriteLine(
    "{0} -> {1} = {2}",xr.Name,xr.NodeType,xr.Value);
    Console.WriteLine("Lecture terminée");
}
  • ProhibitDtd : indique si le traitement d'une DTD est autorisé. Par défaut, les DTD ne sont pas autorisées.
  • ValidationType : indique le type de validation :
  • DTD : validation par une DTD
  • Schema : validation par un schéma XSD
  • XDR : validation par un schéma XDR
  • Auto : validation par une DTD ou schéma associé dans le document XML
  • None : pas de validation (par défaut)
  • ValidationEventHandler : gestionnaire des erreurs de validation. S'il n'y a pas de gestionnaire le XmlReader va lancer une exception XmlException.
  • ValidationFlags : paramètres supplémentaires
  • AllowXmlAttributes : autorise les attributs XML (xml:*) dans le document même si le schéma ne les inclus pas. (non autorisé par défaut)
  • ProcessIdentityConstraints : autorise la validation l'unicité des contraintes d'identité comme xs:ID, xs:IDREF, xs:key, xs:keyref ou xs:unique. (autorisé par défaut)
  • ProcessSchemaLocation : autorise le traitement des informations de localisation des schémas (xsi:schemaLocation et xsi:noNamespaceSchemaLocation) (non autorisé par défaut)
  • ProcessInlineSchema : autorise le traitement des schémas XSD, DTD ou XDR inclus dans le document XML (non autorisé par défaut)
  • ReportValidationWarnings : ajoute des warnings de validation XML. Ces warnings sont notifiés dans le ValidationHandler (désactivé par défaut)
  • XmlResolver : contient un objet XmlResolver permettant de localiser les ressources externes comme les schémas et les DTD ainsi que les include ou import XSD. Par défaut, il s'agit d'une instance de XmlUrlResolver qui accède directement aux URL requises. Voir la section suivante.
  • Schemas : permet de contenir les schémas nécessaires à la validation.

Validation à partir d'un schéma associé au fichier XML

Pour valider un document XML avec schéma qui se trouve référencé par un attribut xsi:schemaLocation ou xsi:noNamespaceSchemaLocation, il faut définir la propriété ValidationFlags du XmlReaderSettings à ProcessSchemaLocation.

//validation d'un fichier XML par un schéma XSD externe
//avec resolver de schéma sécurisé
public static void ValidateExternal_XSD_XmlReader()
{
    //paramètres de validation du reader XML
    XmlReaderSettings settings = new XmlReaderSettings();
    //validation avec schéma XSD
    settings.ValidationType = ValidationType.Schema;
    //autorise les schémas externes uniquement
    //rapporte des warnings de validation
    settings.ValidationFlags =
    XmlSchemaValidationFlags.ProcessSchemaLocation
    | XmlSchemaValidationFlags.ReportValidationWarnings;
 
    //crée un nouveau résolveur de d'url sécurisé qui ne peut lire
    //que dans les sous répertoire de [http://www.sharevb.net/]
    XmlResolver resolver = new XmlSecureResolver(
    new XmlUrlResolver(), "[http://www.sharevb.net/]");

    //affecte les crédits de connexion de l'utilisateur en cours
    //pour s'authentifier sur [http://www.sharevb.net/]
    resolver.Credentials =
    System.Net.CredentialCache.DefaultCredentials;

    //affecte le résolveur aux paramètres de validation
    settings.XmlResolver = resolver;

    //handler de reporting des erreurs de validation
    settings.ValidationEventHandler +=
    new ValidationEventHandler(XmlReader_Validation_Handler);
    
    //crée un reader avec les paramètres
    XmlReader xr =
    XmlReader.Create("Xml\\Samples\\Books_extern_XSD.xml");

    //lit l'ensemble du document pour le valider
    while (xr.Read()) ;
    Console.WriteLine("Validation terminée");
}

Validation à partir d'un schéma non associé au fichier XML

Pour valider un document XML avec un schéma XSD qui se trouve en mémoire ou qui n'est pas associé au document XML (par un attribut schemaLocation), il faut définir la propriété Schemas du XmlReaderSettings pour la remplir avec un XmlSchemaSet contenant des associations entre un espace de nom et le nom du fichier XSD.

//validation d'un fichier XML par un schéma XSD non associé
public static void ValidateNotReferenced_XSD_XmlReader()
{
    //paramètres de validation du reader XML
    XmlReaderSettings settings = new XmlReaderSettings();

    //validation avec schéma XSD
    settings.ValidationType = ValidationType.Schema;

    //crée un conteneur de schéma XSD
   XmlSchemaSet schemaSet = new XmlSchemaSet();

    //charge le schéma XSD de validation dans le conteneur
    //avec l'espace de nom XML [http://www.sharevb.net/BookLib]
    schemaSet.Add(
    "[http://www.sharevb.net/BookLib]",
    "Xml\\Samples\\books.xsd");
   
    //affecte le conteneur de schéma au paramètre de validation
    settings.Schemas = schemaSet;

    //handler de reporting des erreurs de validation
    settings.ValidationEventHandler +=
    new ValidationEventHandler(XmlReader_Validation_Handler);

    //crée un reader avec les paramètres
    XmlReader xr =
    XmlReader.Create("Xml\\Samples\\Books_not_ref_XSD.xml");

    //lit l'ensemble du document pour le valider
    while (xr.Read()) ;
    Console.WriteLine("Validation terminée");
}

Validation à partir d'un schéma inclus dans le fichier XML

Pour valider un document XML incluant un schéma ou une DTD, il faut définir la propriété ValidationFlags du XmlReaderSettings à ProcessInlineSchema. Etant donné que le schéma inline est le premier fils de l'élément racine, la validation donnera un warning indiquant que le noeud racine n'a pas pu être validé (puisque le schéma n'est pas encore connu au début de l'élément racine).

//validation d'un fichier XML par un schéma XSD interne
public static void ValidateInternal_XSD_XmlReader()
{
    //paramètres de validation du reader XML
    XmlReaderSettings settings = new XmlReaderSettings();

    //validation avec schéma XSD
    settings.ValidationType = ValidationType.Schema;

    //autorise les schémas internes uniquement
    //rapporte des warnings de validation
    settings.ValidationFlags =
    XmlSchemaValidationFlags.ProcessInlineSchema
    | XmlSchemaValidationFlags.ReportValidationWarnings;
    
    //handler de reporting des erreurs de validation
    settings.ValidationEventHandler +=
    new ValidationEventHandler(XmlReader_Validation_Handler);

    //crée un reader avec les paramètres
    XmlReader xr =
    XmlReader.Create("Xml\\Samples\\Books_intern_XSD.xml");

    //lit l'ensemble du document pour le valider
    while (xr.Read()) ;
    Console.WriteLine("Validation terminée");
}

Validation à partir d'une DTD

Pour valider un document XML par une DTD associée ou incluse dans le document, il faut définir les propriétés du XmlReaderSettings, ProhibitDtd à false pour autoriser les DTD et ValidationType à DTD.

//validation d'un fichier XML par une DTD
public static void ValidateDTD_XmlReader()
{
    //paramètres de validation
    XmlReaderSettings settings = new XmlReaderSettings();

    //validation avec schéma DTD
    settings.ProhibitDtd = false;
    settings.ValidationType = ValidationType.DTD;

    //handler de reporting des erreurs de validation
    settings.ValidationEventHandler +=
    new ValidationEventHandler(XmlReader_Validation_Handler);

    //crée un reader avec les paramètres
    XmlReader xr =
    XmlReader.Create("Xml\\Samples\\Articles_DTD.xml",
    settings);

    //lit l'ensemble du document pour le valider
    while (xr.Read()) ;
    Console.WriteLine("Validation terminée");
}

Validation d'un XmlNode et XmlDocument

Pour valider un document XmlDocument, il faut utiliser la classe XmlNodeReader que l'on passe à la méthode XmlReader.Create ou au constructeur de XmTextReader :

//validation d'un XmlNode d'un DOM par un schéma XSD
public static void ValidateNodeReader_XmlReader()
{
    //créer un nouveau document XML DOM
    XmlDocument doc = new XmlDocument();

    //charge le fichier XML à valider
    doc.Load("Xml\\Samples\\Articles_XSD.xml");

    //paramètres de validation du reader XML
    XmlReaderSettings settings = new XmlReaderSettings();

    //validation avec schéma XSD
    settings.ValidationType = ValidationType.Schema;

    //schéma XSD externe référencé par un attribut
    //schemaLocation ou noNamespaceSchemaLocation
    settings.ValidationFlags =
    XmlSchemaValidationFlags.ProcessSchemaLocation;

    //handler de reporting des erreurs de validation
    settings.ValidationEventHandler +=
    new ValidationEventHandler(XmlReader_Validation_Handler);
 
    //crée un reader avec les paramètres de validation
    //on utilise un XmlNodeReader pour accéder
    //à un XmlNode sous forme de reader
    XmlReader xr = XmlReader.Create(
    new XmlNodeReader(doc),settings);

    //lit l'ensemble du document pour le valider
    while (xr.Read()) ;
    Console.WriteLine("Validation terminée");
}

Validation par un schéma XDR

La validation d'un document XML avec un schéma XDR peut se faire avec un XmlReader en lui passant un XmlReaderSettings avec la propriété ValidationType défini à XDR..

La validation d'un document XML avec un schéma XDR peut se faire avec un XmlReader en lui passant un XmlReaderSettings avec la propriété ValidationType défini à XDR.

//validation d'un fichier XML par un schéma XDR
public static void ValidateXDR_XmlReader()
{
    //paramètres de validation pour le reader XML
    XmlReaderSettings settings = new XmlReaderSettings();

    //validation avec schéma XDR
    settings.ValidationType = ValidationType.XDR;

    //handler de reporting des erreurs de validation
    settings.ValidationEventHandler +=
    new ValidationEventHandler(XmlReader_Validation_Handler);

    //crée un reader XML avec les paramètres de validation
    XmlReader xr = XmlReader.Create(
    "Xml\\Samples\\Books_XDR.xml", settings);

    //lit l'ensemble du document pour le valider
    while (xr.Read());
    Console.WriteLine("Validation terminée");
}

Validation par un schéma RELAX NG

La validation d'un document XML avec un schéma RELAX NG peut se faire en utilisant le RelaxngValidatingReader de la dll Commons.Xml.Relaxng de Mono.

//validation d'un fichier XMl par un schéma RelaxNG
public static void ValidateRNG()
{
    //crée un reader XML pour le fichier XML
    XmlReader xmlFile =
    XmlReader.Create("Xml\\Samples\\Books_RNG.xml");

    //crée un reader XML pour le fichier de schéma RelaxNG
    XmlReader rngFile =
    XmlReader.Create("Xml\\Samples\\books.rng");

    //crée un validateur XML par schéma RelaxNG
    //à partir du XML et du schéma
    Commons.Xml.Relaxng.RelaxngValidatingReader rngReader =
    new Commons.Xml.Relaxng.RelaxngValidatingReader(
    xmlFile, rngFile);

    //rapport les détails des erreurs de validation
    rngReader.ReportDetails = true;

    try
    {
        //lit l'ensemble du document pour le valider
        while (rngReader.Read()) ;
        Console.WriteLine("Validation terminée");
    }

    //une exception est levée dès la première erreur de validation
    catch (Commons.Xml.Relaxng.RelaxngException re)
    {
        Console.WriteLine("Erreur de validation: {0}", re.Message);
    }

    //ferme tous les readers
    rngReader.Close();
    rngFile.Close();
    xmlFile.Close();
}

Conclusion

Nous avons donc vu qu'un schéma permet de valider le contenu d'un document XML afin qu'il respecte une certaine séquence et forme. Nous avons également vu comment utiliser différents types de schéma et options pour valider les documents XML avec le framework .Net.

A voir également
Ce document intitulé « Les schémas xml et la validation en .net » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous