XML序列化:如何区分使用相同元素名但在属性中具有不同值的类?

时间:2010-12-06 19:48:21

标签: c# .net xml xml-serialization xmlserializer

标题可能很长,让我解释一下我的意思。我不会向您提供我需要使用的实际XML,但我会给出一个证明我所面临的问题的XML。

我有一个如下所示的XML:

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

想象一下以下几类:
(当然这些也不是我真正的课程,但你明白了。)

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; }
}

我希望使用带有属性的XML序列化,我希望序列化程序能够通过MammalCreature属性区分BirdCreaturetype类型。

我找到了可以通过将xsi:type属性设置为我想要的类型名称来实现此解决方案的解决方案,但我想知道是否有一个实际的解决方案可以解决我的问题。

3 个答案:

答案 0 :(得分:2)

不只是属性,没有。但是,这个毛茸茸的代码确实可以将您的XML正确地读入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; }
}

答案 1 :(得分:0)

对于不同类型具有相同的Xml元素名称,这对您来说真的很重要吗?

如果你能像Xml那样生活,你的最终会变得更加简单:

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

答案 2 :(得分:-2)

XML Serializer不支持此方案。