Accueil > .Net, C#, Développement, XML, XSD > Jouer avec le XML – partie 2 – Utilitaire XSD.exe

Jouer avec le XML – partie 2 – Utilitaire XSD.exe

Suite à la première partie sur les généralités XML/XSD, voici un second billet autour du XML.

Cette fois, il sera question de l’usage de XML/XSD en .Net.
Dans cette partie 2, nous verrons comment utiliser l’utilitaire XSD.exe, comment générer une classe à partir d’un XSD puis comment utiliser cette classe.
Dans un billet suivant, nous verrons comment gérer la (dé)sérialisation.
Et enfin, dans un petit dernier, comment valider le XML en fonction d’un XSD.

Voici les billets en rapport :

 

Utilitaire XSD

 

Son emplacement peut visiblement varier.
Mais il est toujours dans un répertoire \SDK\Bin.
Dans mon cas, c’est « C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin ».
Mais il est possible de le trouver également embarqué dans une installation de Visual Studio, par exemple : « C:\Program Files (x86)\Microsoft Visual Studio 9.0\SDK\v3.5\Bin ».

L’utilitaire, selon la MSDN est décrit comme :

L’outil XML Schema Definition Tool (Xsd.exe) génère des classes du Common Language Runtime et du schéma XML à partir de fichiers XDR, XML et XSD ou de classes figurant dans un assembly de runtime.

 

Création d’une classe à partir d’un XSD

 

Pour créer une classe à partir d’un XSD, c’est assez simple.
On va taper la ligne de commande suivante :

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\xsd.exe" SampleXML.xsd /classes /namespace:KR.Sample.XSD

Ici, je me suis bien sûr placé sur le répertoire contenant mon XSD, du coup, l’utilitaire va me générer une classe « SampleXML.cs » qui aura cette tête :

//------------------------------------------------------------------------------
// <auto-generated>
//     Ce code a été généré par un outil.
//     Version du runtime :2.0.50727.5448
//
//     Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
//     le code est régénéré.
// </auto-generated>
//------------------------------------------------------------------------------

// 
// Ce code source a été automatiquement généré par xsd, Version=2.0.50727.3038.
// 
namespace KR.Sample.XSD {
    using System.Xml.Serialization;
    
    
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlRootAttribute("EXPORT", Namespace="", IsNullable=false)]
    public partial class CT_EXPORT {
        
        private CT_HEADER hEADERField;
        
        private CT_USER[] uSERField;
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public CT_HEADER HEADER {
            get {
                return this.hEADERField;
            }
            set {
                this.hEADERField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("USER", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public CT_USER[] USER {
            get {
                return this.uSERField;
            }
            set {
                this.uSERField = value;
            }
        }
    }
    
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    public partial class CT_HEADER {
        
        private string nBUSERSField;
        
        private string dATEEXPORTField;
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="integer")]
        public string NBUSERS {
            get {
                return this.nBUSERSField;
            }
            set {
                this.nBUSERSField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string DATEEXPORT {
            get {
                return this.dATEEXPORTField;
            }
            set {
                this.dATEEXPORTField = value;
            }
        }
    }
    
    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    public partial class CT_USER {
        
        private string iDENTIFIANTField;
        
        private string nOMField;
        
        private string pRENOMField;
        
        private string lOGINField;
        
        private string mAILField;
        
        private string cOMMENTField;
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="integer")]
        public string IDENTIFIANT {
            get {
                return this.iDENTIFIANTField;
            }
            set {
                this.iDENTIFIANTField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string NOM {
            get {
                return this.nOMField;
            }
            set {
                this.nOMField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string PRENOM {
            get {
                return this.pRENOMField;
            }
            set {
                this.pRENOMField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string LOGIN {
            get {
                return this.lOGINField;
            }
            set {
                this.lOGINField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string MAIL {
            get {
                return this.mAILField;
            }
            set {
                this.mAILField = value;
            }
        }
        
        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
        public string COMMENT {
            get {
                return this.cOMMENTField;
            }
            set {
                this.cOMMENTField = value;
            }
        }
    }
}

Alors non, c’est clair, c’est pas très sexy comme classe.
Notamment à cause du nommage des variables qui va faire pleurer tout utilitaire d’analyse de code.
Après, si la classe ne bouge plus, il sera possible de la modifier. Ceci dit, je ne pense quand même pas que ce soit une super idée… (parce que dès que le XSD bouge, va falloir tout se retaper).
Dans ce cas, voir s’il est possible d’exclure les classes générées de l’analyse de code peut être une solution.

 

Utiliser la classe générée

 

Là encore, rien de très compliqué :

CT_EXPORT export = new CT_EXPORT();
export.HEADER = new CT_HEADER();
export.HEADER.DATEEXPORT = DateTime.Now.ToString("ddmmyyyy");
export.HEADER.NBUSERS = "2";

export.USER = new CT_USER[2];

CT_USER user1 = new CT_USER();
user1.IDENTIFIANT = "0000000001";
user1.NOM = "GUYOT";
user1.PRENOM = "FABIEN";
user1.LOGIN = "fguyot";
user1.MAIL = "fguyot@sample.com";
CT_USER user2 = new CT_USER();
user2.IDENTIFIANT = "0000000002";
user2.NOM = "DOE";
user2.PRENOM = "JOHN";
user2.LOGIN = "jdoe";
user2.MAIL = "jdoe@sample.com";
user2.COMMENT = "Le compte est actuellement suspendu & doit être désactivé.";

export.USER[0] = user1;
export.USER[1] = user2;

Plusieurs choses, du coup :

  • Les types integer dans le XSD ne sont pas considérés comme des int en .Net
  • Les utilisateurs (balise USER) sont symbolisés sous la forme d’un tableau
  • Il n’y a aucune validation de type/pattern au niveau de la classe

Mais au final, en sérialisant le bout de code, on obtient un XML assez similaire à celui réalisé à la main :

<?xml version="1.0" encoding="utf-8"?>
<EXPORT>
  <HEADER>
    <NBUSERS>2</NBUSERS>
    <DATEEXPORT>29352012</DATEEXPORT>
  </HEADER>
  <USER>
    <IDENTIFIANT>0000000001</IDENTIFIANT>
    <NOM>GUYOT</NOM>
    <PRENOM>Fabien</PRENOM>
    <LOGIN>fguyot</LOGIN>
    <MAIL>fguyot@sample.com</MAIL>
  </USER>
  <USER>
    <IDENTIFIANT>0000000002</IDENTIFIANT>
    <NOM>DOE</NOM>
    <PRENOM>JOHN</PRENOM>
    <LOGIN>jdoe</LOGIN>
    <MAIL>jdoe@sample.com</MAIL>
    <COMMENT>Le compte est actuellement suspendu &amp; doit être désactivé.</COMMENT>
  </USER>
</EXPORT>

 

Sérialiser la classe

 

Et comme il n’y a pas de mécanisme de sérialisation automatique, voici une petite méthode utile :

        public static void CreationFichierXml<T>(String attributRoot, T xml, String cheminFichierXml, Encoding encodage = null)
        {
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add(String.Empty, String.Empty);
            
            XmlRootAttribute xmlRootAttrib = new XmlRootAttribute(attributRoot);

            XmlWriterSettings settings = new XmlWriterSettings();
            //settings.Encoding = encodage ?? Encoding.UTF8;
            settings.Indent = true;
            //settings.OmitXmlDeclaration = false;

            XmlSerializer serializer = new XmlSerializer(typeof(T), xmlRootAttrib);
            
            using (StreamWriter streamWriter = new StreamWriter(cheminFichierXml, false, encodage))
            {
                using (XmlWriter xmlWriter = XmlWriter.Create(streamWriter, settings))
                {
                    serializer.Serialize(xmlWriter, xml, ns);
                }
            }
        }

Pour l’appeler, on ajoute simplement la ligne :

CreationFichierXml<CT_EXPORT>("EXPORT", export, @"C:\Projects\KR.Samples\XSD\SampleXML.xml", Encoding.UTF8);

A noter, tout de même, le bout de code fournit pour la sérialisation remplace les caractères interdits par leur code HTML.
Du coup, il n’y a plus de présence du CDATA (voir le billet précédent).

Catégories :.Net, C#, Développement, XML, XSD

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :