Десериализовать пару ключ-значение XML в объект класса
У меня есть XML с парой ключ-значение, как указано ниже:
<Employee>
<item>
<key>Name</key>
<value>XYZ</value>
</item>
<item>
<key>Phone</key>
<value>1234567890</value>
</item>
<item>
<key>Date of Birth</key>
<value>19-06-1984</value>
</item>
<item>
<key>Employee ID</key>
<value>1</value>
</item>
</Employee>
И у меня есть класс Property, как указано ниже:
public class Employee
{
public string Name { get; set; }
public string Phone { get; set; }
public DateTime? DOB { get; set; }
public int? Id { get; set; }
}
Мне нужно десериализовать этот XML в класс свойств, но я не понимаю, как правильно добиться этого.
Я могу добиться этого, используя Reflection
но я слышал это Reflection
ухудшает производительность, так что вы хотите знать, есть ли лучший способ добиться этого?
4 ответа
var serializer = new XmlSerializer(typeof(Employee));
using (var reader = new StringReader("Your xml"))
{
var _emp = (Employee)serializer.Deserialize(reader);
var _emp2 = new Employee2()
{
DOB = _emp.Items.Where(x => x.key == "Date of Birth").Select(x => Convert.ToDateTime(x.value)).First(),
Name = _emp.Items.Where(x => x.key == "Name").Select(x => x.value).First(),
Phone = _emp.Items.Where(x => x.key == "Phone").Select(x => x.value).First(),
Id = _emp.Items.Where(x => x.key == "Employee ID").Select(x => Convert.ToInt32(x.value)).First()
};
}
Класс для десериализации
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Employee
{
private EmployeeItem[] itemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("item", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public EmployeeItem[] Items
{
get
{
return this.itemsField;
}
set
{
this.itemsField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class EmployeeItem
{
private string keyField;
private string valueField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string key
{
get
{
return this.keyField;
}
set
{
this.keyField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string value
{
get
{
return this.valueField;
}
set
{
this.valueField = value;
}
}
}
Мне не нравится это решение, потому что сложность больше, чем должна быть. Если бы я столкнулся с этой задачей, я бы использовал autopper. Но я не помню правильный синтаксис для этого.
Воплощать в жизнь IXmlSerializable
как это:
public class Employee : IXmlSerializable
{
public string Name { get; set; }
public string Phone { get; set; }
public DateTime? DOB { get; set; }
public int? Id { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (string.Equals(reader.Name, "item", StringComparison.InvariantCultureIgnoreCase))
{
// move to 'key'
reader.Read();
if (reader.Name != "key") throw new SerializationException();
string key = reader.ReadElementContentAsString();
if (reader.Name != "value") throw new SerializationException();
switch (key)
{
case "Name":
this.Name = reader.ReadElementContentAsString();
break;
case "Phone":
this.Phone = reader.ReadElementContentAsString();
break;
case "Date of Birth":
this.DOB = DateTime.Parse(reader.ReadElementContentAsString());
break;
case "Employee ID":
this.Id = reader.ReadElementContentAsInt();
break;
}
}
else
{
// something was wrong
throw new SerializationException();
}
break;
case XmlNodeType.EndElement:
reader.Read();
return;
}
}
}
public void WriteXml(XmlWriter writer)
{
throw new NotImplementedException();
}
}
И использовать со стандартом XmlSerializer
:
XmlSerializer ser = new XmlSerializer(typeof(Employee));
using (var stream = File.OpenRead(@"D:\Temp\employee.xml"))
{
var item = ser.Deserialize(stream);
}
Это должно сделать это
List<Employee> employees = new List<Employee>();
XElement xElement = XElement.Load("Employees.xml");
IEnumerable<XElement> xmlEmployees = xElement.Elements("Employee");
foreach (var xmlEmployee in xmlEmployees)
{
Employee employee = new Employee();
foreach (var item in xmlEmployee.Elements("item"))
{
string key = item.Element("key").Value;
string value = item.Element("value").Value;
switch (key)
{
case "Name":
employee.Name = value;
break;
...
}
}
employees.Add(employee);
}
You can give this a try. This is simple and subtle.
using System;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Employee emp = new Employee
{
Name = new Item { Key = "Name", Value = "XYZ" },
Phone = new Item { Key = "Phone", Value = "007987" },
DOB = new Item { Key = "Date of Birth", Value = "Some Date"},
Id = new Item { Key = "Employee ID", Value = "A ID" },
};
var ser = new XmlSerializer(typeof(Employee));
using (var fs = new StreamWriter("your path", false))
{
ser.Serialize(fs, emp);
}
var emp2 = ser.Deserialize(new StreamReader("your path"));
}
}
public class Employee
{
[XmlElement(ElementName = "item1")]
public Item Name { get; set; }`enter code here`
[XmlElement(ElementName = "item2")]
public Item Phone { get; set; }
[XmlElement(ElementName = "item3")]
public Item DOB { get; set; }
[XmlElement(ElementName = "item4")]
public Item Id { get; set; }
}
public class Item
{
public string Key { get; set; }
public string Value { get; set; }
}
}