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

发布于 2024-10-06 04:32:55 字数 944 浏览 3 评论 0原文

标题可能有点长,我解释一下我的意思。我不会向您提供我需要使用的实际 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 和 < code>BirdCreature 通过 type 属性。

我找到了可以通过将 xsi:type 属性设置为我想要的类型名称来实现此目的的解决方案,但我想知道是否有一个实际的解决方案可以针对我的情况执行此操作。

The title may be long, let me explain what I mean. I won't give you the actual XML that I need to work with, but I'll give one that demonstrates the issue I'm facing.

I have an XML that looks like this:

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

Imagine the following classes:
(Of course these are not my real classes either, but you get the 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; }
}

I would like to use XML Serialization with attributes in a manner that I want the serializer to distinguish between the types MammalCreature and BirdCreature by the type attribute.

I've found solutions that can do this by setting the xsi:type attribute to the type name I want, but I'd like to know if there is an actual solution that does this for my case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

未央 2024-10-13 04:32:55

不只是属性,不。然而,这段看起来毛茸茸的代码确实可以将您的 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; }
}

Not with just attributes, no. However, this hairy looking code can indeed read your XML properly into a Root class:

[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; }
}
谎言月老 2024-10-13 04:32:55

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

如果您可以接受如下所示的 Xml,那么您最终会变得更加简单:

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

Is it really critical for you to have the same Xml element name for the different types?

Your can end up being much more simple if you can live with the Xml looking like that:

<root>
    <creatures>
        <MammalCreature name="lion">
            <sound>roarr</sound>
        </MammalCreature>
        <Birdcreature name="parrot">
            <color>red</color>
        </BirdCreature>
    </creatures>
</root>
一袭白衣梦中忆 2024-10-13 04:32:55

XML 序列化程序不支持这种情况。

The XML Serializer does not support this scenario.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文