Casey Crookston
Casey Crookston

Reputation: 13965

Convert IEnumerable<XElement> to List<nested object>

I've seen several threads (like this one or this one) that show how to convert an XDocument to a List<> of simple objects, like strings. However, I'm struggling with how to do this with a nested object.

Here's what the XML looks like...

<?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>

And from that XML I've created this class which I now need to get a List<> of...

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; }
}

I'm doing this inside an Azure Blog Storage Trigger funciton. I've gotten this far:

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

Easy enough! customers is indeed the entire IEnumerable of all the Customers in the XML file. Now I just need to go from an

IEnumerable<XElement>

To a

List<DistributorCustomer>

That, I'm not sure how to do. From the other threads, this should be possible with LINQ to XML, and Loop over customers should not be needed.

Upvotes: 2

Views: 2199

Answers (3)

Bosco
Bosco

Reputation: 1554

Why not try Serializing the xml to a list of the object, it is shorter and cleaner

create the base Object

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

then

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);

Upvotes: 1

Casey Crookston
Casey Crookston

Reputation: 13965

OP here. I'm going to leave the answer by DavidG as the correct answer, as he lead me to the solution. But I also want to post the entire answer here, just for posterity.

            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();

Upvotes: 1

DavidG
DavidG

Reputation: 119186

Parsing XML like this using Linq can be quite powerful, maybe not the best way to do it (it's been a while since I used XML) but here is one way making use of Linq Select to project the elements into your types:

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...
        }
    });

Upvotes: 1

Related Questions