【问题标题】:Convert IEnumerable<XElement> to List<nested object>将 IEnumerable<XElement> 转换为 List<nested object>
【发布时间】:2019-07-30 15:13:06
【问题描述】:

我见过几个线程(like this onethis one),它们展示了如何将XDocument 转换为简单对象的List&lt;&gt;,例如字符串。但是,我正在努力解决如何使用嵌套对象来做到这一点。

这就是 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 我创建了这个类,我现在需要得到一个 List&lt;&gt; 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; }
}

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

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

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

IEnumerable<XElement>

到一个

List<DistributorCustomer>

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

【问题讨论】:

    标签: c# .net linq-to-xml


    【解决方案1】:

    像这样使用 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...
            }
        });
    

    【讨论】:

    • 太棒了!谢谢 :) 现在测试一下。
    • 好的,照原样,这给了我一个IEnumerable&lt;DistributorCustomer&gt;。如果我在最后添加一个 .ToList() ,它会引发错误。 `空对象引用'。但我可以弄清楚。可能是因为并非所有 xml 元素都有值。谢谢!
    • 是的,如果缺少元素,你会得到NulReferenceExceptions。您可以通过AccountNumber = c.Element("AccountNumber")?.Value 来缓解这种情况
    【解决方案2】:

    在这里。我将把 DavidG 的答案作为正确答案,因为他会引导我找到解决方案。但我也想在这里发布整个答案,仅供后人参考。

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

    【讨论】:

      【解决方案3】:

      为什么不尝试将 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);
      

      【讨论】:

      • 嗯...这看起来很有趣!我将尝试一下并报告。
      • 好吧,这么说吧,这会在最后一行抛出一个错误。很确定这是因为流包含整个 XML 文件,而不仅仅是&lt;customer&gt;'s。如果我能让这个工作,它肯定是一个更优雅的解决方案。 (旁注:我不需要您的第二行,因为 Azure Blob 存储触发功能会自动将整个文件内容作为流传递给我:blobFile。)
      • 你在使用内存流吗?我实际上尝试将 xml 保存为文件并序列化
      • Azure 函数为我提供了一个 System.IO.Stream,其中包含 blob 文件的内容。在这种情况下,它恰好是一个 XML 文件。为了发帖,我在 OP 中放置的示例进行了编辑。我无法将整个文档序列化为List&lt;DistributorCustomer&gt;。我需要将其缩小到 &lt;customer&gt; 节点。
      • /\ 拼写错误已修复。刷新
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多