【问题标题】:Deserializing XML Based on Element Attributes基于元素属性反序列化 XML
【发布时间】:2018-11-03 02:02:36
【问题描述】:

我正在尝试反序列化 C# 程序中的 XML 文件,如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<Addresses>
  <ListName>Flowers</ListName>
  <Address contextRef="RP.CC">Some Address</Address>
  <Address contextRef="RP.BE">Some Other Address</Address>
  <Address contextRef="RP.BV">Yet Another Address</Address>
  <Address contextRef="RP.CAL">Wow, I Can't Believe It's Another Address</Address>
</Addresses>

我无法控制此文件的格式。但是,它总是有这 4 个 Address 元素的某种组合(即这 4 个 contextRef 属性值是唯一使用的),每次都有不同的元素值。

现在,我需要将它们发送到 Addresses 对象中的各个属性,而不是反序列化为 Address 数组。我当前的实现使用一个数组,然后是一个 setter 方法来根据 contextRef 设置这些属性,如下所示:

public class Addresses
{
    [XmlElement("ListName")]
    public string ListName { get; set; }

    private Address[] _addresses;

    [XmlElement("Address")]
    public Address[] AddressesArray
    {
        get
        {
            return _addresses;
        }
        set
        {
            _addresses = value;
            SetAddress();
        }
    }

    [XmlIgnore]
    public Address AddressG21 { get; set; }

    [XmlIgnore]
    public Address AddressG22 { get; set; }

    [XmlIgnore]
    public Address AddressG23 { get; set; }

    [XmlIgnore]
    public Address AddressG9 { get; set; }

    private void SetAddress()
    {
        foreach (var address in _addresses)
        {
            if (address.ContextRef == "RP.CC")
            {
                AddressG21 = address;
            }
            else if (address.ContextRef == "RP.BE")
            {
                AddressG22 = address;
            }
            else if (address.ContextRef == "RP.BV")
            {
                AddressG23 = address;
            }
            else if (address.ContextRef == "RP.CAL")
            {
                AddressG9 = address;
            }
        }
    }
}

地址对象是这样定义的:

public class Address
{
    private string valueField;

    /// <remarks/>
    [XmlText]
    public string Value
    {
        get
        {
            return this.valueField;
        }
        set
        {
            this.valueField = value;
        }
    }

    [XmlAttribute("contextRef")]
    public string ContextRef { get; set; }
}

所以,我的问题是,是否有一种更简洁/更好的方法可以将此 XML 直接反序列化到 AddressG21 等对象属性中,而无需先使用 Address 数组?

提前致谢。

【问题讨论】:

  • 最简单的方法是使用代理数组属性,如您所示。您可以进行的一项改进是消除private Address[] _addresses; 字段,并在需要时构造并返回数组。或者,您的代理可以是一些自定义ICollection&lt;Address&gt;,它返回指向四个属性的当前值的实时链接。您也可以考虑将 ContextRef 设为枚举,因为只允许使用 4 个值。

标签: c# .net xml deserialization xml-deserialization


【解决方案1】:

我会使用 xml linq 并在类中创建一个字典

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            Addresses addresses = doc.Descendants("Addresses").Select(x => new Addresses() {
                ListName = (string)x.Element("ListName"),
                dict = x.Elements("Address")
                   .GroupBy(y => (string)y.Attribute("contextRef"), z => (string)z)
                   .ToDictionary(y => y.Key, z => z.FirstOrDefault())
            }).FirstOrDefault();

        }
    }
    public class Addresses
    {
        public string ListName { get; set; }
        public Dictionary<string, string> dict { get; set; }
    }

}

如果你有多个 Addresses 元素,那么使用这个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            List<Addresses> addresses = doc.Descendants("Addresses").Select(x => new Addresses() {
                ListName = (string)x.Element("ListName"),
                dict = x.Elements("Address")
                   .GroupBy(y => (string)y.Attribute("contextRef"), z => (string)z)
                   .ToDictionary(y => y.Key, z => z.FirstOrDefault())
            }).ToList();

        }
    }
    public class Addresses
    {
        public string ListName { get; set; }
        public Dictionary<string, string> dict { get; set; }
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多