将 IEnumerable<XElement> 转换为 List<nested object>

Convert IEnumerable<XElement> to List<nested object>

我看过几个讨论帖 (like this one or this one),它们展示了如何将 XDocument 转换为简单对象(如字符串)的 List<>。但是,我正在为如何使用嵌套对象执行此操作而苦苦挣扎。

这是 XML 的样子...

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
.... other stuff removed to make reading easier ....
            <ListOfCustomers>
                <Customer>
                    <CustomerName>A TO Z Fubar</CustomerName>
                    <AccountNumber>A TO001</AccountNumber>
                    <BillingAddress>
                        <Address1>11900 W FUBAR AVE</Address1>
                        <Address2/>
                        <City>FUBAR</City>
                        <State>CO</State>
                        <Zip>80215</Zip>
                        <Country>US</Country>
                    </BillingAddress>
                    <ShippingAddress>
                        <Address1>11900 W FUBAR AVE</Address1>
                        <Address2/>
                        <City>FUBAR</City>
                        <State>CO</State>
                        <Zip>80215</Zip>
                        <Country>US</Country>
                    </ShippingAddress>
                </Customer>
                <Customer>....</Customer>
                <Customer>....</Customer>
            </ListOfCustomers>

然后 XML 我创建了这个 class 现在我需要得到一个 List<> 的...

public class DistributorCustomer
{
    public string CustomerName { get; set; }
    public string AccountNumber { get; set; }
    public BillingAddress BillingAddress { get; set; }
    public ShippingAddress ShippingAddress { get; set; }
}


public class BillingAddress
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
    public string Country { get; set; }
}

public class ShippingAddress
{
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
    public string Country { get; set; }
}

我在 Azure 博客存储触发器函数中执行此操作。我已经走到这一步了:

XDocument xDoc = XDocument.Load(blobFile);
IEnumerable<XElement> customers = xDoc.Descendants("Customer");

很简单! customers 确实是 XML 文件中所有客户的全部 IEnumerable。现在我只需要从

IEnumerable<XElement>

给一个

List<DistributorCustomer>

那个,我不知道该怎么做。从其他线程来看,这应该可以通过 LINQ to XML 实现,并且不需要循环 customers

像这样使用 Linq 解析 XML 可能非常强大,也许不是最好的方法(自从我使用 XML 以来已经有一段时间了)但这是一种利用的方法Linq Select 将元素投影到您的类型中:

var customers = xDoc.Descendants("Customer")
    .Select(c => new DistributorCustomer
    {
        CustomerName = c.Element("CustomerName").Value,
        AccountNumber = c.Element("AccountNumber").Value,
        BillingAddress = new BillingAddress
        {
            Address1 = c.Element("BillingAddress").Element("Address1").Value,
            // etc...
        }
    });

为什么不尝试将 xml 序列化为对象列表,它更短更清晰

创建基础对象

public class ListOfCustomers
{
    [XmlElement("Customer")]
    public List<DistributorCustomer> Customer { get; set; }
}

然后

XmlSerializer ser = new XmlSerializer(typeof(ListOfCustomers));
FileStream myFileStream = new FileStream(/*file path*/); //if you are using a file. use Memory stream for xml string
var thelist =  (ListOfCustomers)ser.Deserialize(myFileStream);

OP在这里。我将把 DavidG 的答案作为正确答案,因为他会引导我找到解决方案。但我也想post这里的整个答案,只是为了post严肃。

            List<DistributorCustomer> customerList = xDoc.Descendants("Customer")
            .Select(c => new DistributorCustomer
            {
                CustomerName = c.Element("CustomerName")?.Value,
                AccountNumber = c.Element("AccountNumber")?.Value,
                BillingAddress = new BillingAddress
                {
                    Address1 = c.Element("BillingAddress")?.Element("Address1")?.Value,
                    Address2 = c.Element("BillingAddress")?.Element("Address2")?.Value,
                    City = c.Element("BillingAddress")?.Element("City")?.Value,
                    State = c.Element("BillingAddress")?.Element("State")?.Value,
                    Zip = c.Element("BillingAddress")?.Element("Zip")?.Value,
                    Country = c.Element("BillingAddress")?.Element("Country")?.Value,
                },
                ShippingAddress = new ShippingAddress
                {
                    Address1 = c.Element("ShippingAddress")?.Element("Address1")?.Value,
                    Address2 = c.Element("ShippingAddress")?.Element("Address2")?.Value,
                    City = c.Element("ShippingAddress")?.Element("City")?.Value,
                    State = c.Element("ShippingAddress")?.Element("State")?.Value,
                    Zip = c.Element("ShippingAddress")?.Element("Zip")?.Value
                }
            }).ToList();