【问题标题】:How to deserialzie XML object based on attribute value of the child object c#?如何根据子对象c#的属性值反序列化XML对象?
【发布时间】:2019-08-13 12:46:01
【问题描述】:

如何根据子对象的属性值反序列化XML对象?

例如我得到了这个

<List>
  <Person>
    <M id= Name v="Chris">
    <M id= Year v="12">
    <M id= Haircolor v="blond">
    <M id= HairLength v="10">
  </Person >
  <Person>
    <M id= Name v="Sara">
    <M id= Year v="9">
    <M id= Haircolor v="Brown">
    <M id= HairLength v="20">
  </Person >
  <Person>
    <M id= Name v="Noelle">
    <M id= Year v="20">
    <M id= Haircolor v="Gray">
    <M id= HairLength v="30">
  </Person >      <Person>
</List>

如何反序列化?我使用 XElement 仅选择后代(“Person”),然后我将获取 Person 的所有 XML 部分。 我的问题是,由于所有元素都具有相同的 ElementName = M,我不知道如何将每个元素 M 分隔为类属性值。我尝试做 XMLElement("M"),但它会将所有内容解释为相同。一个对我有用的解决方案是在 XmlElement 中使用“顺序”,但这种方法不是防弹的,因为您有时可以获得空值,因此会将值放在错误的类属性中。

在这种情况下,我得到了一个看起来像这样的模型:

public class Person 
{    
  public string Name {get; set;}
  public string Year {get; set;}      
  public string Haircolor {get; set;}      
  public string HairLength {get; set;}
}

我希望 Id name 的 M 元素对应 class 中的 Name,而 M 元素中的 ID year 对应 Year etc...

我怎样才能做到这一点?

【问题讨论】:

  • 你能反序列化 XML 吗?如果你是,那么这就是大部分的战斗。不要尝试将其直接反序列化到您的 Person 类中。相反,将其反序列化为任何内容,然后将其映射到您想要的最终类。换句话说,将你不想要的“奇怪”反序列化类转换成你想要的更好的类。
  • 我设法反序列化它很好,但我的问题是例如因为我使用订单值,每当 Name 元素没有值时,年份值自动落入 Name 属性...跨度>

标签: c# xml


【解决方案1】:

给定一个加载了 XML 的 XmlDocument,这将使用 XPath 查询来解析文件:

IEnumerable<Person> ReadPeople(XmlDocument document)
{
    var result = new List<Person>();
    var root = document.DocumentElement;
    var personNodes = root.SelectNodes("Person");
    foreach (XmlElement personNode in personNodes)
    {
        var person = new Person
        {
            Name = personNode.SelectSingleNode("M[@id='Name']")?.Attributes["v"]?.Value,
            Haircolor = personNode.SelectSingleNode("M[@id='Haircolor']")?.Attributes["v"]?.Value,
            HairLength = personNode.SelectSingleNode("M[@id='HairLength']")?.Attributes["v"]?.Value,
            Year = personNode.SelectSingleNode("M[@id='Year']")?.Attributes["v"]?.Value
        };

        result.Add(person);
    }
    return result;
}

例子:

var document = new XmlDocument();
document.Load(File.OpenRead("XmlFile1.xml"));
var people = ReadPeople(document);

它执行以下操作:

  • 选择根元素中的所有 Person 节点
  • 对于每个 Person 节点,选择具有每个预期 id 属性的 M 元素,并将 v 属性的值分配给 Person 对象的相应属性。

为了我的测试,我必须清理 XML 的某些方面,所以我正在加载的文档如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<List>
  <Person>
    <M id= "Name" v="Chris"/>
    <M id= "Year" v="12"/>
    <M id= "Haircolor" v="blond"/>
    <M id= "HairLength" v="10"/>
  </Person >
  <Person>
    <M id= "Name" v="Sara"/>
    <M id= "Year" v="9"/>
    <M id= "Haircolor" v="Brown"/>
    <!--<M id= "HairLength" v="20"/>-->
  </Person >

</List>

原件格式不正确 - 缺少结束标记和属性值周围的引号。

这包括删除一个元素以确保正确处理空值。


或者,如果您更喜欢重复性稍低的内容,您可以使用本地函数来检索给定的 id 并使用 LINQ 查询。

IEnumerable<Person> ReadPeople(XmlDocument document)
{
    string GetAttribute(XmlElement personNode, string id) =>
        personNode.SelectSingleNode($"M[@id='{id}']")?.Attributes["v"]?.Value;

    return document.DocumentElement.SelectNodes("Person").Cast<XmlElement>()
        .Select(node =>
            new Person
            {
                Name = GetAttribute(node, "Name"),
                Haircolor = GetAttribute(node, "Haircolor"),
                HairLength = GetAttribute(node, "HairLength"),
                Year = GetAttribute(node, "Year")
            });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多