IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Framework .NET Discussion :

Sérialisation XML partielle.


Sujet :

Framework .NET

  1. #1
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut Sérialisation XML partielle.
    Bonjour tout le monde.
    Je cherche, sans succès, un moyen de faire une sérialisation/dé sérialisation partielle en XML.
    Je m'explique, j'ai des classes que je ne peux pas modifier et dont je cherche à effectuer une sérialisation/dé sérialisation en spécifiant les propriétés concernées par la sérialisation.

    Voici un exemple pour être plus clair :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // Une classe que je veux sérialiser, je ne peux pas la modifier, de quelque façon que ce soit
    public class MaClassSerialisable
    {
        [UnAttributCustom(2)] public string Valeur1 { get; set; }
        [UnAttributCustom(2)] public string Valeur2 { get; set; }
     
        [UnAttributCustom(8)] public string Valeur3 { get; set; }
        [UnAttributCustom(8)] public string Valeur4 { get; set; }
    }

    J'aimerai pourvoir sérialiser l'objet mais en spécifiant "2" ou "8", pour que le fichier résultant ne contienne que les propriétés affectées par l'attribut correspondant.
    Donc si je spécifie 2, le fichier résultant doit être :
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    <?xml version="1.0" encoding="utf-8"?>
    <MaClassSerialisable>
        <Valeur1>bla bla bla</Valeur1>
        <Valeur2>truc</Valeur2>
    </MaClassSerialisable>

    Seulement voila, je ne trouve pas d'autres solutions que de ré-inventer entièrement le XmlSerializer...
    Personne n'aurait une solution à ce problème ? Merci d'avance

    EDIT : La demande est pour la sérialisation ET la dé-sérialisation. Les propriétés manquantes dans le fichier XML devront rester à leurs valeur par défaut.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Il y a un moyen de personnaliser la sérialisation d'une classe quand tu ne peux pas la modifier, en utilisant XmlAttributeOverrides. Plus d'infos ici :
    http://tlevesque.developpez.com/dotn...zation/#LIII-D

  3. #3
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Merci pour la réponse, je n'avais pas compris comment s'utilise ce constructeur.
    Cependant, je ne dois pas avoir tout compris pour autant, vu que ça me lance une exception lors de la sérialisation
    Les attributs XmlRoot et XmlType peuvent ne pas être spécifiés pour le type MaClassSerialisable.
    Pour le moment je n'ai tenté que la sérialisation, voici mon code : :

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    // La fonction de sérialisation
    private void Serialize(MaClasseSerialisable o, string fileName, int v)
    {
    	Type t = o.GetType();
    	XmlAttributeOverrides attrs = new XmlAttributeOverrides();
    	AddOverrideAttribute(attrs, t, v);
     
    	XmlSerializer xser = new XmlSerializer(t, attrs);
    	using (StreamWriter sw = new StreamWriter(fileName))
    	{
    		xser.Serialize(sw, configuration);
    	}
    }
     
    // --------------------------------------------------------
     
    // Cette méthode construit récursivement les attributs de sérialisation
    private void AddOverrideAttribute(XmlAttributeOverrides attributes, Type t, int vl)
    {
    	if (t != null && attributes != null && attributes[t] == null)
    	{
    		XmlAttributes xattrs = new XmlAttributes();
    		//xattrs.XmlRoot = new XmlRootAttribute(t.Name);
    		//xattrs.XmlType = new XmlTypeAttribute(t.Name);
    		PropertyInfo[] props = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    		foreach (PropertyInfo p in props)
    		{
    			object[] attrs = p.GetCustomAttributes(typeof(UnAttributCustomAttribute), true);
    			if (attrs.Length == 1)
    			{
    				UnAttributCustomAttribute c = attrs[0] as UnAttributCustomAttribute;
    				if (c.Value == v)
    				{
    					xattrs.XmlElements.Add(new XmlElementAttribute(p.Name));
    					if(!p.PropertyType.IsValueType && p.PropertyType != typeof(string))
    						AddOverrideAttribute(attributes, p.PropertyType, level);
    				}
    			}
    		}
    		if(xattrs.XmlElements.Count > 0)
    			attributes.Add(t, xattrs);
    	}
    }

    J'ai testé en spécifiant un XmlRoot et un XmlType (j'ai tenté en le mettant dans la fonction AddOverrideAttribute, comme les commentaires le montrent, mais j'ai également tenté dans le fonction se sérialisation afin de les placer uniquement sur la classe racine).

    Ma fonction est recursive afin de pouvoir suivre les propriétés typées avec d'autres classes du même genre.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Je ne comprends pas trop pourquoi tu as besoin de XmlRoot et XmlType... du molns pour l'exemple que tu as donné. L'élément prend par défaut le nom du type, donc inutile de le préciser. Et l'attribut XmlType sert à indiquer un type XSD, ce n'est sans doute pas ce que tu veux.

    Tu peux faire ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        var overrides = new XmlAttributeOverrides();
        overrides.Add(typeof(MaClassSerialisable), "Valeur3", new XmlAttributes { XmlIgnore = true });
        overrides.Add(typeof(MaClassSerialisable), "Valeur4", new XmlAttributes { XmlIgnore = true });
     
        var xs = new XmlSerializer(typeof(MaClassSerialisable), overrides);
    Et ça donne le résultat que tu voulais (+ des déclarations de namespaces qui n'ont pas beaucoup d'importance)

    Après, je n'ai pas compris tout ce que tu cherchais à faire, il faudrait que tu donnes plus de détails sur ta structure de classe et sur le sens de UnAttributCustomAttribute...

  5. #5
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Je ne comprends pas trop pourquoi tu as besoin de XmlRoot et XmlType... du moins pour l'exemple que tu as donné. L'élément prend par défaut le nom du type, donc inutile de le préciser. Et l'attribut XmlType sert à indiquer un type XSD, ce n'est sans doute pas ce que tu veux.
    Bah moi non plus je vois pas pourquoi, j'avais bien compris la même chose alors ^^'.


    Citation Envoyé par tomlev Voir le message
    JTu peux faire ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        var overrides = new XmlAttributeOverrides();
        overrides.Add(typeof(MaClassSerialisable), "Valeur3", new XmlAttributes { XmlIgnore = true });
        overrides.Add(typeof(MaClassSerialisable), "Valeur4", new XmlAttributes { XmlIgnore = true });
     
        var xs = new XmlSerializer(typeof(MaClassSerialisable), overrides);
    Et ça donne le résultat que tu voulais (+ des déclarations de namespaces qui n'ont pas beaucoup d'importance)
    Humm, spécifier les propriétés à ignorer plutôt que celles à sérialiser, bonne idée. Par contre je vais perdre la possibilité de sérialiser les propriétés non publiques. Je ne suis pas certain de pouvoir m'en passer.

    Citation Envoyé par tomlev Voir le message
    Après, je n'ai pas compris tout ce que tu cherchais à faire, il faudrait que tu donnes plus de détails sur ta structure de classe et sur le sens de UnAttributCustomAttribute...
    Les classes en question sont simples comme celle de mon exemple, seulement une partie des données doit aller dans un fichier, l'autre partie doit aller dans un autre fichier. Le fichier de destination de chaque propriété dépends de la valeur de certains attributs.
    Mais ce sont des classes pour lesquelles je n'ai pas la main. Mon code fait office de colle entre deux softs qui ne sont pas fait pour bosser ensemble, et via reflexion j'ai trouvé mon bonheur via ces attributs personnalisés, a condition que cette histoire d'XmlAttributeOverrides fonctionne ^^'

    Je testerai pas ce soir par contre. Y'avait le pot de bienvenue d'un collègue, et je ne veux pas tester le coup de la ballmer's peak ce soir pour un truc qui doit être en prod début de semaine prochaine ^^'.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par ctxnop Voir le message
    Par contre je vais perdre la possibilité de sérialiser les propriétés non publiques. Je ne suis pas certain de pouvoir m'en passer.
    Bah de toutes façons la sérialisation XML ne sérialise que les membres publics. Et si ce sont des classes dont tu ne maitrises pas le code, tu n'y a pas accès non plus à partir de ton code...

    Citation Envoyé par ctxnop Voir le message
    Les classes en question sont simples comme celle de mon exemple, seulement une partie des données doit aller dans un fichier, l'autre partie doit aller dans un autre fichier. Le fichier de destination de chaque propriété dépends de la valeur de certains attributs.
    Mais ce sont des classes pour lesquelles je n'ai pas la main. Mon code fait office de colle entre deux softs qui ne sont pas fait pour bosser ensemble, et via reflexion j'ai trouvé mon bonheur via ces attributs personnalisés, a condition que cette histoire d'XmlAttributeOverrides fonctionne ^^'
    Dans ce genre de cas, le plus simple est sans doute de créer tes propres classes sur lesquelles tu as complètement la main, et de les mapper sur les classes que tu veux sérialiser (soit en copiant les propriétés à la main, soit avec un outil comme AutoMapper)

    Citation Envoyé par ctxnop Voir le message
    Je testerai pas ce soir par contre. Y'avait le pot de bienvenue d'un collègue, et je ne veux pas tester le coup de la ballmer's peak ce soir pour un truc qui doit être en prod début de semaine prochaine ^^'.
    ah bon ? je comprends pas pourquoi tu dis ça

  7. #7
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    La sérialisation XML par défaut ne sérialise que ce qui est publique (sauf si la classe implémente IXmlSerialisable, dans ce cas ce qui est sérialisé dépend de l'implémentation). Mais théoriquement rien n'empêcherai la sérialisation de membres non publiques. La sérialisation fonctionne par la réflexion, les valeurs obtenues le sont aussi par réflexion, donc si je pouvais spécifier une liste des PropertyInfo à sérialiser, publiques ou non, ça passerai.

    Pour le moment, dans mon cas, je n'ai pas encore besoin des membres privés, donc je vais faire avec.
    Cependant, je ne peux pas me permettre de faire un mappage manuel ou d'utiliser un truc genre automapper, le problème étant que le soft génère des tonnes de classes de ce genre au moment du runtime. Du coup je ne peux pas préconstruire des mappages. Je dois tout faire au runtime aussi.

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par ctxnop Voir le message
    La sérialisation fonctionne par la réflexion, les valeurs obtenues le sont aussi par réflexion
    En fait pas vraiment, c'est un peu plus compliqué que ça... La première fois que tu crées un XmlSerializer d'un type donné, ça génère dynamiquement (*) une nouvelle classe dédiée pour sérialiser ce type. Et cette classe n'utilise pas la réflexion, elle accède directement aux propriétés du type à sérialiser... la réflexion n'est utilisée que pour générer la classe de sérialisation. Ce qui explique pourquoi les membres privés ne sont pas sérialisables...

    Plus de détails ici :
    http://tlevesque.developpez.com/dotn...ation-2/#LIV-A

  9. #9
    Membre expérimenté Avatar de ctxnop
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juillet 2007
    Messages
    858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2007
    Messages : 858
    Points : 1 732
    Points
    1 732
    Par défaut
    Youpi ça marche !
    Effectivement pour le coup de la génération de l'assembly, après vérification avec reflector, il génère bien un assembly.
    Cependant, rien n'empêcherait qu'il génère le code nécessaire à l'obtention des valeurs via reflexion pour les membres non publiques.
    Enfin bon, ce n'est pas bien grave, a priori je n'en aurai pas besoin.

    Il ne me reste plus qu'un truc à trouver. Dans la mesure où la sérialisation produit plusieurs fichiers, il me faut un moyen pour dé-sérialiser en utilisant le même objet de destination.

Discussions similaires

  1. Problème de sérialisation XML d'une Array
    Par Abakai dans le forum C#
    Réponses: 3
    Dernier message: 21/05/2007, 15h30
  2. Sérialisation xml : fichier xml vide
    Par casafa dans le forum C#
    Réponses: 1
    Dernier message: 25/04/2007, 15h13
  3. [C# 2.0] Sérialisation XML avec PCDATA
    Par stailer dans le forum C#
    Réponses: 2
    Dernier message: 07/01/2007, 22h52
  4. Problème sérialisation XML [C#]
    Par AlphonseBrown dans le forum Windows Forms
    Réponses: 4
    Dernier message: 27/04/2006, 22h58
  5. [VB.NET] Sérialisation XML de Collections
    Par nico-pyright(c) dans le forum Windows Forms
    Réponses: 8
    Dernier message: 15/12/2004, 15h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo