【问题标题】:XML Deserialize with same element name and different attributes​ name具有相同元素名称和不同属性名称的 XML 反序列化
【发布时间】:2017-04-07 07:48:37
【问题描述】:

我想在 C# 中反序列化以下 XML

<Test>
<Testdata>
<abc name = "fname"> Test</abc>
<abc name = "lname"> Name</abc
</Testdata>
</Test>

我有一个小例子,我有更大的 XML 需要反序列化为 .Net 对象!!下面是我的对象

Public class Employee
{
      Public string LastName {get; set;}
      Public string FirstName {get;set;}
}

如何使用 linq 或 XML 序列化程序反序列化此类 xml。

目前我正在使用 xdocument,获取名称为 abc 的所有节点并使用 if else 阶梯构造对象,但这不是正确的方法。

测试是名字 名称是 XML 中的姓氏..

任何帮助将不胜感激!

【问题讨论】:

  • 我可以检查一下...TestFirstName 的值吗?NameLastName 的值?
  • @marc 是的先生!!

标签: c# xml linq xml-serialization


【解决方案1】:

您描述的映射不是XmlSerializer 支持的映射。如果没有以下之一,您将无法以这种方式序列化 Employee

  • 实施IXmlSerializable - 我确实推荐;很容易把它弄得一团糟,尤其是反序列化代码
  • 通过XDocumentXmlDocument 手动完成(同样,工作量很大)
  • 创建一个可从XmlSerializer 使用且与您的架构匹配的 DTO 模型

坦率地说,我会使用最后一个选项,这可能意味着创建类似的东西(完全未经测试,但我会在一分钟内尝试):

[XmlRoot("Test")]
public class DtoRoot {
    [XmlArray("Testdata")]
    [XmlArrayItem("abc")]
    public List<KeyValuePair> Items {get;} = new List<KeyValuePair>();

    public string this[string key] => Items.FirstOrDefault(x => x.Key == key)?.Value;
}
public class KeyValuePair{
    [XmlAttribute("name")]
    public string Key {get;set;}
    [XmlText]
    public string Value {get;set;}
}

并使用类似的东西:

Employee emp = new Employee
{
    FirstName = "Fred",
    LastName = "Flintstone"
};
var obj = new DtoRoot {
    Items = {
    new KeyValuePair { Key = "fname", Value = emp.FirstName },
    new KeyValuePair { Key = "lname", Value = emp.LastName},
} };
var ser = new XmlSerializer(typeof(DtoRoot));
ser.Serialize(Console.Out, obj);

这给了我们(忽略encoding - 那是因为Console.Out):

<?xml version="1.0" encoding="ibm850"?>
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Testdata>
    <abc name="fname">Fred</abc>
    <abc name="lname">Flintstone</abc>
  </Testdata>
</Test>

要反序列化:反序列化为DtoRoot 实例,然后使用索引器:

var obj = (DtoRoot)ser.Deserialize(source);
var emp = new Employee {
    FirstName = obj["fname"],
    LastName = obj["lname"],
};

【讨论】:

    【解决方案2】:

    使用 xdocument 而非序列化将 xml 解析为类并没有错。这是一个不用else ladder的方法

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    
    
    namespace ConsoleApplication49
    {   
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XDocument doc = XDocument.Load(FILENAME);
    
                Employee.employees = doc.Descendants("Testdata").Select(x => new Employee()
                {
                    FirstName = x.Elements().Where(y => (string)y.Attribute("name") == "fname").Select(y => (string)y).FirstOrDefault(),
                    LastName = x.Elements().Where(y => (string)y.Attribute("name") == "lname").Select(y => (string)y).FirstOrDefault()
                }).ToList();
    
            }
        }
        public class Employee
        {
            public static List<Employee> employees = new List<Employee>();
    
            public string LastName {get; set;}
            public string FirstName {get;set;}
        }
    
    
    }
    

    【讨论】:

    • 没有比任何其他 xml 方法快或慢。只有当你有巨大的 xml 文件时,使用 XmlReader 才值得。在这种情况下,速度与您的 xml 样式有关,对名字和姓氏使用相同的标签。
    • 我相信你处理空值的条件很大?
    • 您发布了示例代码,所以我不确定是否需要进行空值检查。
    【解决方案3】:

    在此处使用列表。

    public class Employee
    {
        public static List<Employee> employees = new List<Employee>();
    
        public Listc<string> Name {get; set;}
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-14
      • 1970-01-01
      • 1970-01-01
      • 2015-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多