从InnerText和Value属性反序列化XML元素

时间:2015-10-15 09:12:35

标签: c# .net xml

我有XML Serializable类,其属性名称为

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

我希望它能够以两种方式反序列化我拥有的XML文件:

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

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

第一个工作正常,但我应该做些什么才能在同一个类中反序列化第二个?

3 个答案:

答案 0 :(得分:2)

XML序列化属性适用于序列化和反序列化。如果我们假设可以使用属性从两个不同的xml结构反序列化Item的实例,那么序列化应该如何工作 - 它应该将实例名称序列化为元素值,还是属性?或两者兼而有之?这就是为什么你不能将两个不同的xml结构反序列化为单个类。使用两个不同的类或手动反序列化它而不使用XML序列化属性。

答案 1 :(得分:0)

由于您已经提到XML数据来自外部来源,所以很明显您无法控制它。

因此,您可以按照以下任意选项进行操作:

  1. 为每个XML数据结构创建单独的类,因为据我所知,在使用XmlSerializer
  2. 时无法控制XML反序列化
  3. 您可以使用XDocument自行阅读XML,以克服此限制。
  4. 如果按照第二个想法,我已经创建了一个小型控制台应用程序来演示。

    主要代码如下:

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

    我在这里使用LinqToXml读取元素并检查元素是否为空,即Value不为空,然后使用Value,否则从元素中读取值Attribute

    控制台应用程序(完整代码):

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

    注意:要运行此功能,您需要在项目中添加对System.Xml.Linq.dll的引用。

    参考:here

答案 2 :(得分:0)

我找到另一种方法来解决我的问题,只使用一个类,也许有人会发现这个有用的

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

也许它不是超级优雅但它适用于两种情况并且使用相同的类。