SÉRIALISATION XML D'UN DICTIONARY

hsaturn Messages postés 14 Date d'inscription jeudi 6 octobre 2005 Statut Membre Dernière intervention 3 juin 2007 - 3 juin 2007 à 02:32
elassas Messages postés 3 Date d'inscription mardi 25 novembre 2008 Statut Membre Dernière intervention 24 juillet 2009 - 24 juil. 2009 à 17:31
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

elassas Messages postés 3 Date d'inscription mardi 25 novembre 2008 Statut Membre Dernière intervention 24 juillet 2009
24 juil. 2009 à 17:31
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
}
}
godvicien Messages postés 36 Date d'inscription dimanche 23 janvier 2005 Statut Membre Dernière intervention 6 avril 2014
18 avril 2008 à 12:27
Très bon code, je mets 8/10.
nargho Messages postés 1 Date d'inscription dimanche 16 juillet 2006 Statut Membre Dernière intervention 7 octobre 2007
7 oct. 2007 à 20:18
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)
BaFM Messages postés 64 Date d'inscription mercredi 24 juillet 2002 Statut Membre Dernière intervention 26 novembre 2009
16 juin 2007 à 15:48
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...
hsaturn Messages postés 14 Date d'inscription jeudi 6 octobre 2005 Statut Membre Dernière intervention 3 juin 2007
3 juin 2007 à 02:32
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 :-)
Rejoignez-nous