Reputation: 13965
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
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
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
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