SÉRIALISATION XML D'UN DICTIONARY

Signaler
Messages postés
14
Date d'inscription
jeudi 6 octobre 2005
Statut
Membre
Dernière intervention
3 juin 2007
-
Messages postés
3
Date d'inscription
mardi 25 novembre 2008
Statut
Membre
Dernière intervention
24 juillet 2009
-
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/40912-serialisation-xml-d-un-dictionary

Messages postés
3
Date d'inscription
mardi 25 novembre 2008
Statut
Membre
Dernière intervention
24 juillet 2009

Voilà une autre solution :

Dans cette classe je sérialise un Dictionary en binaire et en XML, pour tester la classe il suffit de faire une classe qui contient une méthode main() et bien evidemement créer un dico le sérialiser puis le désérialiser bon bref ça je pense aue tout le monde sais le faire.

J'ai aussi créer une méthode Display() pour afficher les dico afin de vérifier si l'objet est bien sérialisé et bien désérialisé.

Si vous avez des questions je suis joignable par mail.

Code de ma classe :

namespace Dictionary
{
using System;
using System.Collections;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Xml.Serialization;

[Serializable]
public class Dictionary<TKey, TValue> : System.Collections.Generic.Dictionary<TKey, TValue>, IXmlSerializable, ISerializable
{
#region FIELDS
public enum SerializationLevel
{
Minimal,
Full
}
private SerializationLevel _SerializationLevel;
#endregion

#region ISerializable Members
/// <summary>
///
/// </summary>
///

///

public Dictionary(SerializationInfo info, StreamingContext context)
{
SerializationInfoEnumerator InfoEnumerator = info.GetEnumerator();
while (InfoEnumerator.MoveNext())
{
System.Collections.DictionaryEntry DE = (System.Collections.DictionaryEntry)InfoEnumerator.Value;
this.Add((TKey)DE.Key, (TValue)DE.Value);
//System.Collections.Generic.KeyValuePair<TKey, TValue> kpv = (System.Collections.Generic.KeyValuePair<TKey, TValue>)InfoEnumerator.Value;
//this.Add(kpv.Key, kpv.Value);
}
}
/// <summary>
///
/// </summary>
///

///

[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
public new virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info != null)
foreach (System.Collections.Generic.KeyValuePair<TKey, TValue> kpv in this)
info.AddValue(kpv.Key.ToString(), new System.Collections.DictionaryEntry(kpv.Key, kpv.Value), typeof(System.Collections.DictionaryEntry));
//info.AddValue(kpv.Key.ToString(), kpv, typeof(System.Collections.Generic.KeyValuePair<TKey, TValue>));
}
#endregion

#region Constructors
/// <summary>
///
/// </summary>
public Dictionary()
: base()
{
this._SerializationLevel = Dictionary<TKey, TValue>.SerializationLevel.Full;
}
/// <summary>
///
/// </summary>
///

public Dictionary(SerializationLevel serializationLevel)
: base()
{
this._SerializationLevel = serializationLevel;
}
#endregion

#region IXmlSerializable Members
/// <summary>
///
/// </summary>
/// <returns></returns>
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
/// <summary>
///
/// </summary>
///

public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(DictionaryEntry));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty) return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
DictionaryEntry KP = (DictionaryEntry)xmlSerializer.Deserialize(reader);
this.Add((TKey)KP.Key, (TValue)KP.Value);
reader.MoveToContent();
}
reader.ReadEndElement();
}
/// <summary>
///
/// </summary>
///

public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
if (this._SerializationLevel == Dictionary<TKey, TValue>.SerializationLevel.Full)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(System.Collections.DictionaryEntry), new Type[] { typeof(TValue), typeof(TKey) });
foreach (System.Collections.Generic.KeyValuePair<TKey, TValue> kpv in this)
{
xmlSerializer.Serialize(writer, new System.Collections.DictionaryEntry(kpv.Key, kpv.Value));
}
}
else
{
XmlSerializer deSerializer = new XmlSerializer(typeof(DictionaryEntry));
foreach (System.Collections.Generic.KeyValuePair<TKey, TValue> kpv in this)
{
deSerializer.Serialize(writer, new DictionaryEntry((TKey)kpv.Key, (TValue)kpv.Value), ns);
}
}
}
#endregion

#region Methods
public void Display()
{
IDictionaryEnumerator myEnumerator = this.GetEnumerator();
while (myEnumerator.MoveNext())
Console.WriteLine(myEnumerator.Key.ToString() + " : " + myEnumerator.Value.ToString());
Console.WriteLine();
}
#endregion
}
}
Messages postés
36
Date d'inscription
dimanche 23 janvier 2005
Statut
Membre
Dernière intervention
6 avril 2014

Très bon code, je mets 8/10.
Messages postés
1
Date d'inscription
dimanche 16 juillet 2006
Statut
Membre
Dernière intervention
7 octobre 2007

Salut,

Le code a très bien marché pour moi, mais j'ai trouvé une petite erreur dans la désérialisation.
Si on a par exemple deux dictionnaires a remplir à partir d'un fichier xml tel que :

<DicoClients>
<clients-fr>
<Client NomClient="toto" />
<Client NomClient="toto2" />
</clients-fr>
<clients-en>
...
</clients-en>
</DicoClients>

Dans la classe :

[XmlRoot("DicoClients")]
public class DicoClients
{
private Clients _clientsFr;
[XmlElement("clients-fr")]
public Clients ClientsFr
{
get { return _clientsFr; }
set { _clientsFr = value; }
}

private Clients _clientsEn;
[XmlElement("clients-en")]
public Clients ClientsEn
{
get { return _clientsEn; }
set { _clientsEn = value; }
}
}

Le problème est que la désérialisation du premier dictionnaire se fait bien mais pas la 2ème. Pour corriger cela, il faut modifier la méthode ReadXml :

public void ReadXml(System.Xml.XmlReader reader)
{
reader.Read(); // move past container
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
Client value = (Client)new XmlSerializer(typeof(Client)).Deserialize(reader);
reader.MoveToContent();
monDictionnaire.Add(value.m_NomClient,value);
}
reader.Read(); // <---------- On se place sur l'élément suivant
}

Voilou :o)
Messages postés
64
Date d'inscription
mercredi 24 juillet 2002
Statut
Membre
Dernière intervention
26 novembre 2009

Quelques éléments de réponse aux questions :
- Dans WriteXml, la clef du dictionnaire génère la balise <string>dur</string>, Comment obtenir <Clef>dur</Clef>, sans transformer le String en objet ?
En faut, il faut utilise XmlAttributeOverrides pour ajouter la prise en compte de nouveaux attributs personnalisés. Ou alors, juste donner un nom d'élément racine lors de la création du serialiseur.

- Est-il possible de forcer la sérialisation d'un champs "private" : m_DateNaissance ?
Il me semble, d'après la documentation, que lorsque le type n'est pas une collection et donc que ses champs publics sont sérialisés, quand on ajoute l'interface IXmlSerializable, celle-ci permet de rajouter les données XML de notre choix. Mais je me trompe peut-être. J'ai pas essayé, mais il y a un exemple.

Sinon, il est mieux je pense d'enregistrer tes serialiseurs dans des champs static. Ce qui permet de ne pas le reconstruire. Mais ptet qu'il y a une sorte de système de correspondance pour ne pas recréer une assembly à chaque noouvelle instance de serialiseur...
Messages postés
14
Date d'inscription
jeudi 6 octobre 2005
Statut
Membre
Dernière intervention
3 juin 2007

Bonjour

Grand merci pour ce code.

J'ai eu beaucoup de mal à faire fonctionner le fichier txt (sic).
Mais ça a l'air de fonctionner correctement. Je vais utiliser ce bout de code très sympa :-)