2015-10-15 1 views
2

je classe sérialisable XML avec la propriété Nomélément XML Deserialize de InnerText et valeur de l'attribut

[Serializable] 
public class Item 
{ 
    [XmlElement("name")] 
    public string Name { get; set; } 
} 

et je veux qu'il soit en mesure de désérialiser fichier XML que j'ai de deux façons:

<item> 
    <name>Name</name> 
</item> 

et

<item> 
    <name value="Name" /> 
</item> 

les premiers travaux, mais bien que dois-je faire pour pouvoir désérialiser le seco Sommes-nous aussi avec la même classe?

+0

IMO ce n'est pas possible. Vous devrez finaliser le format des fichiers XML d'entrée. C'est une question intéressante cependant. – niksofteng

Répondre

0

Je trouve une autre façon de résoudre mon problème en utilisant une personne seule classe peut-être trouverez ce utile

[Serializable] 
public class Item 
{ 
    [XmlElement("name")] 
    public NameElement NameElement { get; set; } 
} 

public class NameElement 
{ 
    [XmlAttribute("value")] 
    public string Value { get; set; } 

    [XmlText] 
    public string Text { get; set; } 

    [XmlIgnore] 
    public string Name 
    { 
     get { return String.IsNullOrEmpty(this.Value) ? this.Text : this.Value; } 
     set { this.Value = value; } 
    } 
} 

Peut-être que c'est pas super élégant, mais cela fonctionne dans les deux cas et utilise la même classe.

2

Les attributs de sérialisation XML fonctionnent à la fois avec la sérialisation et la désérialisation. Si nous supposons qu'il peut être possible d'utiliser des attributs pour désérialiser l'instance de Item à partir de deux structures xml différentes, alors comment la sérialisation devrait fonctionner - devrait-elle sérialiser le nom d'instance en valeur d'élément, ou attribuer? Ou aux deux? C'est pourquoi vous ne pouvez pas désérialiser deux structures xml différentes en une seule classe. Utilisez deux classes différentes ou désérialisez-les manuellement sans utiliser les attributs de sérialisation XML.

+0

A droite, j'ai pensé que le texte interne de l'élément xml est en quelque sorte traduit en attribut value. J'utilise une API externe et en fonction de la requête, j'obtiens des items avec différents éléments de convention de nom:/ – Brazol

+1

Alors la meilleure solution pour toi est probablement de créer une autre classe 'Item2' pour différentes conventions (bien sûr tu devrais utiliser un meilleur nom qui décrit différence entre vos types de demande). Et désérialiser la réponse à 'Item2' si vous envoyez une requête de type différent. Vous pouvez faire en sorte que 'Item' et' Item2' implémentent la même interface. Ainsi, d'autres parties de votre code peuvent l'utiliser sans connaître le type exact que vous avez transmis. –

0

Puisque vous avez mentionné que les données XML proviennent de sources externes, vous n'avez évidemment aucun contrôle sur ces données.

Par conséquent, vous pouvez suivre l'une des options comme ci-dessous:

  1. Créer une classe séparée par structure de données XML, parce que jusqu'à présent, je sais qu'il n'y a aucun moyen de contrôler XML Désérialisation lors de l'utilisation XmlSerializer
  2. Vous pouvez utilisez XDocument pour lire le code XML par vous-même, afin de surmonter cette limitation.

Si j'y vais par seconde idée, j'ai créé une petite application console pour le démontrer.

pièce principale de code est comme ci-dessous:

MemoryStream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)); 
XDocument doc = XDocument.Load(xmlStream); 

var records = from record in doc.Descendants("item").Descendants() 
       select new Item(!record.IsEmpty ? record.Value : record.Attribute("value").Value); 

Ici, je lis l'élément à l'aide LinqToXml et vérifier si l'élément est pas vide, ce Value est pas vide, puis utilisez Value lire autrement la valeur de Attribute de l'élément.

application Console (code complet):

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Xml.Linq; 
using System.Xml.Serialization; 

namespace Console.TestApp 
{ 
    class Program 
    { 
     static string xmltypeFirst = @"<item> 
    <name>John</name> 
</item>"; 

     static string xmltypeSecond = @"<item> 
    <name value='Smith' /> 
</item>"; 

     static void Main(string[] args) 
     { 
      var data = xmltypeFirst; 
      var result = Deserialize(data).ToList(); 
      Console.WriteLine("Name: " + result[0].Name); 

      data = xmltypeSecond; 
      result = Deserialize(data).ToList(); 
      Console.WriteLine("Name: " + result[0].Name); 

      Console.WriteLine("Press any to key to exit.."); 
      Console.ReadLine(); 
     } 

     private static IEnumerable<Item> Deserialize(string xmlData) 
     { 
      MemoryStream xmlStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)); 
      XDocument doc = XDocument.Load(xmlStream); 

      var records = from record in doc.Descendants("item").Descendants() 
          select new Item(!record.IsEmpty ? record.Value : record.Attribute("value").Value); 
      return records; 
     } 
    } 

    [Serializable] 
    public class Item 
    { 
     public Item(string name) 
     { 
      this.Name = name; 
     } 

     [XmlElement("name")] 
     public string Name { get; set; } 
    } 
} 

Remarque: Pour exécuter cela, vous devrez ajouter une référence à System.Xml.Linq.dll dans votre projet.

Référence: here

+0

Bonne idée mais mon exemple était seulement pour illustrer le problème et le xml est beaucoup plus compliqué donc il faudrait beaucoup plus de travail pour le désérialiser en utilisant XmlDocument que d'utiliser la classe Serializable. – Brazol