2010-12-06 25 views
2

Le titre peut être long, laissez-moi vous expliquer ce que je veux dire. Je ne vais pas vous donner le code XML avec lequel je dois travailler, mais je vais en donner un qui montre le problème auquel je suis confronté.Sérialisation XML: comment distinguer les classes utilisant le même nom d'élément mais ayant une valeur différente dans un attribut?

J'ai un fichier XML qui ressemble à ceci:

<root> 
    <creatures> 
     <creature type="mammal" name="lion"> 
      <sound>roarr</sound> 
     </creature> 
     <creature type="bird" name="parrot"> 
      <color>red</color> 
     </creature> 
    </creatures> 
</root> 

Imaginez les classes suivantes: (. Bien sûr, ce ne sont pas mes vraies classes non plus, mais vous obtenez le point)

public class Creature 
{ 
    public string Name { get; set; } 
} 

public class MammalCreature : Creature 
{ 
    public string Sound { get; set; } 
} 

public class BirdCreature : Creature 
{ 
    public string Color { get; set; } 
} 

Je voudrais utiliser la sérialisation XML avec des attributs de manière à ce que le sérialiseur fasse la distinction entre les types MammalCreature et BirdCreature par l'attribut type.

J'ai trouvé des solutions qui peuvent faire cela en affectant l'attribut xsi:type au nom de type que je veux, mais j'aimerais savoir s'il existe une solution réelle pour mon cas.

Répondre

2

Pas seulement avec des attributs, non. Cependant, ce code à la recherche velue peut en effet lire votre XML correctement dans une classe Root:

[XmlRoot("root")] 
public class Root : IXmlSerializable 
{ 
    [XmlElement("creatures")] 
    public Creatures Items { get; set; } 

    /// <summary> 
    /// This method is reserved and should not be used. When implementing 
    /// the IXmlSerializable interface, you should return null (Nothing in 
    /// Visual Basic) from this method, and instead, if specifying a custom 
    /// schema is required, apply the 
    /// <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> 
    /// to the class. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the 
    /// XML representation of the object that is produced by the 
    /// <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> 
    /// method and consumed by the 
    /// <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> 
    /// method. 
    /// </returns> 
    public XmlSchema GetSchema() 
    { 
     return null; 
    } 

    /// <summary> 
    /// Generates an object from its XML representation. 
    /// </summary> 
    /// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream 
    /// from which the object is deserialized. </param> 
    public void ReadXml(XmlReader reader) 
    { 
     reader.ReadStartElement("root"); 
     reader.ReadStartElement("creatures"); 

     List<Creature> creatures = new List<Creature>(); 

     while ((reader.NodeType == XmlNodeType.Element) 
      && (reader.Name == "creature")) 
     { 
      Creature creature; 
      string type = reader.GetAttribute("type"); 
      string name = reader.GetAttribute("name"); 

      reader.ReadStartElement("creature"); 

      switch (type) 
      { 
       case "mammal": 
        MammalCreature mammalCreature = new MammalCreature(); 

        reader.ReadStartElement("sound"); 
        mammalCreature.Sound = reader.ReadContentAsString(); 
        reader.ReadEndElement(); 
        creature = mammalCreature; 
        break; 
       case "bird": 
        BirdCreature birdCreature = new BirdCreature(); 

        reader.ReadStartElement("color"); 
        birdCreature.Color = reader.ReadContentAsString(); 
        reader.ReadEndElement(); 
        creature = birdCreature; 
        break; 
       default: 
        reader.Skip(); 
        creature = new Creature(); 
        break; 
      } 

      reader.ReadEndElement(); 
      creature.Name = name; 
      creature.Type = type; 
      creatures.Add(creature); 
     } 

     reader.ReadEndElement(); 
     this.Items = new Creatures(); 
     this.Items.Creature = creatures.ToArray(); 
     reader.ReadEndElement(); 
    } 

    /// <summary> 
    /// Converts an object into its XML representation. 
    /// </summary> 
    /// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> stream 
    /// to which the object is serialized. </param> 
    public void WriteXml(XmlWriter writer) 
    { 
     new XmlSerializer(typeof(Creatures)).Serialize(writer, this.Items); 
    } 
} 

[XmlRoot("creatures")] 
public class Creatures 
{ 
    [XmlElement("creature")] 
    public Creature[] Creature { get; set; } 
} 

[XmlInclude(typeof(MammalCreature))] 
[XmlInclude(typeof(BirdCreature))] 
public class Creature 
{ 
    [XmlAttribute("type")] 
    public string Type { get; set; } 

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

public class MammalCreature : Creature 
{ 
    [XmlElement("sound")] 
    public string Sound { get; set; } 
} 

public class BirdCreature : Creature 
{ 
    [XmlElement("color")] 
    public string Color { get; set; } 
} 
+0

+1 Merci pour votre réponse! Oui, je pensais que l'implémentation d'IXmlSerializable me donnerait une solution, même si je cherchais une solution KISS. Peut-être que je vais convaincre la personne qui a créé le schéma de le modifier d'une manière prise en charge par la sérialisation XML basée sur les attributs. – Venemo

+0

Je sais que c'est long après que cette réponse a été postée, mais j'ai quelques problèmes avec cette façon de faire les choses. – Hewins

+0

@Hewins Ensuite, vous devriez poster une nouvelle question avec ce que vous avez fait et les problèmes exacts que vous rencontrez. –

0

Est-il vraiment essentiel que vous ayez le même nom d'élément Xml pour les différents types?

Votre peut finir par être beaucoup plus simple si vous pouvez vivre avec le Xml regarder comme ça:

<root> 
    <creatures> 
     <MammalCreature name="lion"> 
      <sound>roarr</sound> 
     </MammalCreature> 
     <Birdcreature name="parrot"> 
      <color>red</color> 
     </BirdCreature> 
    </creatures> 
</root> 
+0

Je suis d'accord, mais il est évident que je ne suis pas le seul responsable de la création du schéma XML. – Venemo

-2

Le sérialiseur XML ne supporte pas ce scénario.