2

J'essaie de sérialiser un dictionnaire en C#. Tous theexamples que je suis en mesure de trouver créer XML comme suit:IXmlSerializable dictionary in C# sans nœuds 'Key'/'Value'

<Dictionary> 
    <ArrayOfEntries> 
     <Entry> 
      <Key>myFirstKey</Key> 
      <Value>myFirstValue</Value> 
     </Entry> 
     <Entry> 
      <Key>mySecondKey</Key> 
      <Value>mySecondValue</Value> 
     </Entry> 
    </ArrayOfEntries> 
</Dictionary> 

Il varie, parfois le nœud ArrayOfEntries est pas nécessaire, mais je vois toujours le modèle régulier des paires clé-valeur du dictionnaire étant stockés dans leurs propres nœuds. Ce que je voudrais quelque chose comme ce qui suit:

<Dictionary> 
    <myFirstKey>myFirstValue</myFirstKey> 
    <mySecondKey>mySecondValue</mySecondKey> 
</Dictionary> 

J'ai écrit ReadXml et WriteXml de le faire avant et il fonctionne pour un seul dictionnaire, mais si je tente de sérialiser et désérialiser un List<T> de mes instances sérialisables dictionnaire , la liste deserialized se termine avec seulement le dernier dictionnaire sérialisable en elle. Je pense que quelque chose doit être gourmand à propos de ma méthode de lecture ou d'écriture de sorte qu'elle ne sache pas quand s'arrêter. Voici mes sérialisables méthodes de dictionnaire qui actuellement ne fonctionnent pas pour la sérialisation des List « s de dictionnaires sérialisables:

public void WriteXml(XmlWriter writer) 
{ 
    foreach (string key in getKeysToSerialize()) 
    { 
     string cleanKey = key.SanitizeForXml(); 
     string value = getValueForKey(key).Trim(); 

     if (isCdata(key, value)) 
     { 
      string cdataFriendlyValue = cleanStringForUseInCdata(value); 
      if (string.IsNullOrEmpty(cdataFriendlyValue)) 
      { 
       continue; 
      } 

      writer.WriteStartElement(cleanKey); 
      writer.WriteCData(cdataFriendlyValue); 
      writer.WriteEndElement(); 
     } 
     else 
     { 
      writer.WriteElementString(cleanKey, value); 
     } 
    } 
} 

Et ReadXml:

public void ReadXml(XmlReader reader) 
{ 
    string key = null, value = null; 
    bool wasEmpty = reader.IsEmptyElement; 

    while (reader.Read()) 
    { 
     if (wasEmpty) 
     { 
      return; 
     } 

     switch (reader.NodeType) 
     { 
      case XmlNodeType.Element: 
       key = reader.Name; 
       if (keyIsSubTree(key)) 
       { 
        using (XmlReader subReader = reader.ReadSubtree()) 
        { 
         storeSubtree(key, subReader); 
        } 

        // Reset key to null so we don't try to parse it as 
        // a regular key-value pair later 
        key = null; 
       } 
       break; 
      case XmlNodeType.Text: 
       value = reader.Value; 
       break; 
      case XmlNodeType.CDATA: 
       value = cleanCdataForStoring(reader.Value); 
       break; 
      case XmlNodeType.EndElement: 
       if (!string.IsNullOrEmpty(key)) 
       { 
        string valueToStore = 
         string.IsNullOrEmpty(value) ? string.Empty : value 
        Add(key, valueToStore); 
       } 
       key = null; 
       value = null; 
       break; 
     } 
    } 
} 

Une différence que j'ai remarqué entre autres tutoriels et ce Je fais est que beaucoup utilisent XmlSerializer pour sérialiser et désérialiser les objets dans leurs ReadXml et WriteXml, alors que j'utilise WriteElementString et similaires. Ma question est, comment est-ce que je peux sérialiser un dictionnaire tel que son XML est comme mon deuxième exemple XML ci-dessus, mais de sorte que la sérialisation et la désérialisation d'un List<MySerializableDictionary> fonctionne également? Même juste des allusions de "pourquoi faites-vous blah, qui pourrait le faire agir drôle" aiderait.

+0

Supposons-nous que votre dictionnaire est un Dictionary ici? – insipid

+0

@insipid, whoops, oui c'est 'Dictionary '. –

Répondre

1

Mon WriteXml semblait correct, car il affiche le contenu du dictionnaire au format XML que je veux. ReadXml était où je me trompais. Sur la base de la mise en œuvre ReadXml trouvé in this tutorial, je suis venu avec ce qui suit:

public override void ReadXml(XmlReader reader) 
{ 
    reader.MoveToContent(); 
    bool isEmptyElement = reader.IsEmptyElement; 
    reader.ReadStartElement(); 
    if (isEmptyElement) 
    { 
     return; 
    } 
    while (XmlNodeType.EndElement != reader.NodeType) 
    { 
     // Bypass XmlNodeType.Whitespace, as found in XML files 
     while (XmlNodeType.Element != reader.NodeType) 
     { 
      if (XmlNodeType.EndElement == reader.NodeType) 
      { 
       reader.ReadEndElement(); 
       return; 
      } 
      reader.Read(); 
     } 
     string key = reader.Name; 
     if (keyIsSubTree(key)) 
     { 
      storeSubtree(key, reader.ReadSubtree()); 
     } 
     else 
     { 
      string value = reader.ReadElementString(); 
      storeKeyValuePair(key, value ?? string.Empty); 
     } 
    } 
    if (XmlNodeType.EndElement == reader.NodeType) 
    { 
     reader.ReadEndElement(); 
    } 
} 

Cela a semblé fonctionner pour les dictionnaires qui ont une seule paire clé-valeur, ainsi que des dictionnaires avec plusieurs paires clé-valeur. Mon test de sérialisation/désérialisation d'un List<T> de dictionnaires a également fonctionné. Je n'ai pas encore ajouté de traitement spécial pour CDATA, et je suis sûr que cela sera nécessaire. Cela semble être un début, cependant.

Edit: En fait, peut-être je besoin que de s'inquiéter CDATA quand je suis écrit, pas lors de la lecture.

Edit: mis à jour le code ReadXml ci-dessus pour expliquer XmlNodeType.Whitespace, qui se trouve dans des fichiers XML lorsque vous désérialisation. Je recevais une erreur XML parce que ReadEndElement était appelée lorsque le reader.NodeType n'était pas un XmlNodeType.EndElement. Mettez un chèque pour cela il appelle seulement ReadEndElement quand il est un EndElement, et a également changé la boucle while externe afin que le lecteur peut progresser (via Read()) quand il n'a pas touché un Element et il n'a pas touché un EndElement (par exemple, il a frappé Whitespace).

+0

L'utilisateur peut également fournir des clés avec des caractères non valides, bien que vous les "désinfectiez". Cela affecte l'unicité des clés de votre fichier XML. – insipid