3

Je xml comme ceci:C# Désérialise avec IXmlSerializable

<data>  
    <audit_values> 
    <audit_value> 
     <channel>2</channel> 
     <week> 
     <mo_th>6,501698000000</mo_th> 
     <fr>8,414278000000</fr> 
     <sa>9,292674000000</sa> 
     <sun>8,551982000000</sun> 
     <holid>7,164605000000</holid> 
     </week> 
    </audit_value> 
    <audit_value> 
     <channel>1</channel> 
     <week> 
     <mo_th>6,501698000000</mo_th> 
     <fr>8,414278000000</fr> 
     <sa>9,292674000000</sa> 
     <sun>8,551982000000</sun> 
     <holid>7,164605000000</holid> 
     </week> 
    </audit_value> 
    </audit_values> 
</data> 

Et je dois désérialiser la classe. Mais le problème est, cette semaine sera le changement à l'avenir (il sera contient plus d'éléments, et le nom d'entre eux, je ne sais pas)

données:

[XmlRoot("data")] 
public class Data 
{ 
    [XmlArray("audit_values")] 
    [XmlArrayItem("audit_value", IsNullable = true)] 
    public AuditValue[] AuditValues { get; set; } 
} 

AuditValue:

[XmlRoot("audit_value")] 
public class AuditValue 
{ 
    [XmlElement("week", typeof(TVR))] 
    public Week Week; 
} 

semaine:

[XmlRoot("week")] 
public class Week : IXmlSerializable 
{ 
    public Dictionary<string, double> Values = new Dictionary<string, double>(); 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     reader.Read(); 
     var sub = reader.ReadSubtree(); 
     do 
     { 
      if (sub.NodeType == XmlNodeType.Element) 
      { 
       string name = sub.Name; 
       string val = sub.ReadElementContentAsString(); 
       Values.Add(name, Convert.ToDouble(val)); 
      } 
     } while (sub.Read()); 
    } 

    public void WriteXml(XmlWriter writer) 
    { 

    } 
} 

Mais après deserializat Je n'ai qu'un seul élément avec un seul dans les valeurs du dictionnaire. Qu'est-ce que je fais mal?

GitHub: https://github.com/olegletynain/XmlTest/tree/master/XmlTestRead

+0

Possible duplication de [désérialiser types aléatoires/inconnus avec XmlSerializer] (http: // stackoverflow.com/questions/8210386/deserialize-aléatoire-inconnu-types-avec-xmlserializer) – GSerg

+0

Désolé, mais j'ai un problème dans l'implémentation de IXmlSerializable et il n'y a pas de types inconnus. Ce n'est pas un doublon –

+0

Avez-vous essayé d'ajouter un point d'arrêt et de déboguer votre code? –

Répondre

2

J'ai modifié votre méthode de ReadXml basée sur l'idée de @Matthew Whited dans la section des commentaires et la méthode suivante fait le travail:

public void ReadXml(XmlReader reader) 
{ 
    Values = XElement.Parse(reader.ReadOuterXml()) 
     .Elements() 
     .ToDictionary(k => k.Name.ToString(), v => double.Parse(v.Value)); 
} 

Comme un côté vous notez seulement besoin XmlRoot sur l'élément racine réelle pas sur tous les classe donc je l'ai enlevé de AuditValue et Week. Aussi je ne sais pas ce qu'est TVR. Il n'a pas compilé avec "typeof (TVR)" donc je l'ai enlevé aussi bien.

Par souci d'exhaustivité, voici ma version des classes:

[XmlRoot("data")] 
public class Data 
{ 
    [XmlArray("audit_values")] 
    [XmlArrayItem("audit_value", IsNullable = true)] 
    public AuditValue[] AuditValues { get; set; } 
} 

public class AuditValue 
{ 
    [XmlElement("week")] 
    public Week Week; 
} 

public class Week : IXmlSerializable 
{ 
    public Dictionary<string, double> Values = new Dictionary<string, double>(); 

    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(XmlReader reader) 
    { 
     Values = XElement.Parse(reader.ReadOuterXml()) 
      .Elements() 
      .ToDictionary(k => k.Name.ToString(), v => double.Parse(v.Value)); 
    } 

    public void WriteXml(XmlWriter writer) 
    { 

    } 
} 
+0

Merci, cette nuit une méthode faite par moi-même, sans utiliser XElement et Linq –

0

essayer. XmlElement élimine une couche de balises que vous n'avez pas. Vous avez un extra à la fin des valeurs.

From 
    [XmlArray("audit_values")] 
    [XmlArrayItem("audit_value", IsNullable = true)] 
    public AuditValue[] AuditValues { get; set; } 
​To 
    [XmlElement("audit_value")] 
    public AuditValue[] AuditValues { get; set; } 
+0

Oh, désolé, la première fois c'était une erreur dans xml. –

+0

Vous n'avez pas besoin de deux niveaux de tags et juste . Utiliser XlEement au lieu de XmlArray élimine les balises inutiles. – jdweng

+0

Désolé, mais vous avez tort –

1

Vous devriez envisager d'utiliser DataContractSerializer au lieu de XmlSerializer et mettre en œuvre l'interface IExtensibleDataObject sur votre classe DataContract. L'implémentation de IExtensibleDataObject permet à la classe DataContract de conserver les informations inconnues dans le champ ExtensionData, ce qui évite qu'elle soit perdue si le XML en cours de désérialisation contient des éléments inconnus, puis est re-sérialisé et enregistré.

Votre classe de vérification ressemblerait à quelque chose comme ceci:

[DataContract(Name = "audit_value", Namespace = "")] 
public class AuditValue : IExtensibleDataObject 
{ 
    [DataMember(Name = "channel")] 
    public int Channel { get; set; } 

    [DataMember(Name = "week")] 
    public Week Week { get; set; } 

    public ExtensionDataObject ExtensionData { get; set; } 
} 

[DataContract(Name = "week", Namespace = "")] 
public class Week : IExtensibleDataObject 
{ 
    [DataMember(Name = "mo_th")] 
    public Decimal MondayThroughThursday { get; set; } 

    public ExtensionDataObject ExtensionData { get; set; } 
} 

Vous devez toujours mettre à jour votre code pour désérialiser les éléments supplémentaires comme Poços, mais au moins les données sous-jacentes sera persisté jusqu'à ce que vous obtenez autour à lui.

0

L'erreur était dans la méthode ReadXml, maintenant je l'ai changé à ceci:

public void ReadXml(XmlReader reader) 
    { 
     reader.Read(); 
     do 
     { 
      if (!reader.IsEmptyElement) 
      { 
       var name = reader.Name; 
       var val = Convert.ToDouble(reader.ReadElementContentAsString()); 
       Values.Add(name, val); 
      } 
      else 
      { 
       reader.Skip(); 
      } 
     } while (reader.Name != "week"); 
     if (reader.NodeType == XmlNodeType.EndElement) 
     { 
      reader.ReadEndElement(); 
     } 
    } 

Et je fonctionne très bien. Cette solution sans utiliser XElement et Linq, @Volkan Paksoy offert la méthode avec XElement qui est plus facile à comprendre