【问题标题】:Read attribute/value pairs from XML file using Linq使用 Linq 从 XML 文件中读取属性/值对
【发布时间】:2013-02-18 13:35:33
【问题描述】:

我有一个如下所示的 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<response uri="/crm/private/xml/Leads/getRecords">
   <Leads>
      <row no="1">
         <FL val="LEADID">2000000022020</FL>
         <FL val="SMOWNERID">2000000018005</FL>
         <FL val="Lead Owner">John</FL>
         <FL val="Company">Zillium</FL>
         <FL val="First Name">Scott</FL>
         <FL val="Last Name">James</FL>
         <FL val="Designation">null</FL>
         <FL val="Email">null</FL>
         <FL val="Phone">null</FL>
         <FL val="Fax">null</FL>
         <FL val="Mobile">null</FL>
         <FL val="Website">null</FL>
         <FL val="Lead Source">null</FL>
         <FL val="Lead Status">null</FL>
         <FL val="No of Employees">0</FL>
         <FL val="Annual Revenue">0.0</FL>
      </row>
      <row no="2">
         <FL val="LEADID">2000000022020</FL>
         <FL val="SMOWNERID">2000000018005</FL>
         <FL val="Lead Owner">John</FL>
         <FL val="Company">Zillium</FL>
         <FL val="First Name">Scott</FL>
         <FL val="Last Name">James</FL>
         <FL val="Designation">null</FL>
         <FL val="Email">null</FL>
         <FL val="Phone">null</FL>
         <FL val="Fax">null</FL>
         <FL val="Mobile">null</FL>
         <FL val="Website">null</FL>
         <FL val="Lead Source">null</FL>
         <FL val="Lead Status">null</FL>
         <FL val="No of Employees">0</FL>
         <FL val="Annual Revenue">0.0</FL>
      </row>
   </Leads>
</response>

我正在尝试读取行元素中的“键/值”对,但我似乎无法掌握如何使用 Linq 来做到这一点。

我需要将数据“反序列化”成一个简单的 POCO

public class Leads
{
    public long LEADID { get; set; }
    public long SMOWNERID { get; set; }
    public string LeadOwner { get; set; }
    public string Company { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Designation { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string Fax { get; set; }
    public string Mobile { get; set; }
    public string Website { get; set; }
    public string LeadSource { get; set; }
    public string LeadStatus { get; set; }
    public int NoOfEmployees { get; set; }
    public decimal AnnualRevenue { get; set; }
}

我的问题是,所有元素都具有相同的名称,因此我需要将属性值 (val) 与元素值配对。

所以我的问题是,有没有一种聪明的方法可以使用 Linq 做到这一点。

否则我的解决方法是编写一个 XLS 并将 XML 转换为更可反序列化的 XML 格式。

【问题讨论】:

  • 使用 linq to xml 是可行的,但 XSLT 会更好更优雅,请参阅Deserialize elements to properties based on attribute
  • @Rafal 你是绝对正确的,这就是我通常会做的事情。但这个问题是因为我想了解更多关于 Linq 的信息;)

标签: c# xml linq-to-xml deserialization


【解决方案1】:

您可以选择每个值,例如

let company = (string)r.Elements()
                       .Single(x => (string)x.Attribute("val") == "Company")

但我相信将所有元素投影到字典中会更快(并且更具可读性)

var query = 
     xdoc.Descendants("row")
         .Select(r => r.Elements().ToDictionary(f => (string)f.Attribute("val")))
         .Select(d => new Leads {
             LEADID = (long)d["LEADID"],
             SMOWNERID = (long)d["SMOWNERID"],
             Company = (string)d["Company"]
             // etc
         });

另外请记住,您需要对前两个属性使用 long(根据示例 xml 中的值)。

【讨论】:

  • 那么返回什么?什么类型的查询,如何从 Leads 对象中获取数据?
  • @Verakso 查询是IEnumerable&lt;Leads&gt;。与程序中的任何其他对象一样使用潜在客户对象。您可以将它们转换为列表 var leadsList = query.ToList() 或简单地在 foreach 循环中使用
  • 我选择了这个答案,因为它比其他很好的例子更容易调试。我不仅学到了一些关于 Linq 的东西,还学到了一个新的 Lambda 表达式——汗水。
  • 我注意到该示例使用显式强制转换,例如Company = (string)d["Company"]但是写Company = d["Company"].Value.ToString()不是更合适吗?
  • @Verakso 显式转换允许您将属性值转换为 long、int、DateTime 等。同样在操作符内部实现为 Int64.Parse(attribute.Value)
【解决方案2】:
var xdoc = XDocument.Parse(xmlstring);
xdoc.Elements("response").Elements("Leads").Elements("row").Select(l => new Leads() 
{
    LEADID = (long)l.Elements("FL").Where(fl => (string)fl.Attribute("val") == "LEADID").FirstOrDefault(),
    SMOWNERID = (long)l.Elements("FL").Where(fl => (string)fl.Attribute("val") == "SMOWNERID").FirstOrDefault(),
    etc..
});

【讨论】:

  • 你不是说:LEADID = (int)l.Elements("FL").Where((string)l.Attribute("val") == "LEADID").FirstOrDefault(), 我还能错过什么吗?我收到 System.Xml.Linq.XElement 不包含 Where...的定义的错误...
  • 对不起,我有一个错误。我已经更新了帖子,希望现在可以工作。确保包含“使用 System.Xml.Linq;”
  • @Tallek:你还有一个错字:Elements("Response") 必须是Elements("response"),否则你会得到一个空列表。
  • 是否需要像本例中那样进行遍历,使用xdoc.Descendants("row").Select(.... 可以轻松完成
  • @Verakso 这应该也可以。我只是更喜欢对我想要的东西更具体一点。如果你知道 xml 永远不会改变,那很好,但如果由于某种原因添加了一个新元素,它下面也有 'row' 元素,你不想突然被打破。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
相关资源
最近更新 更多