2013-03-20 60 views
-1

我有具有多个Invoice元素的XML输入。我从这些元素创建发票对象。根据发票元素的位置,我们需要分配序列号并从不同的元素 - StatusMsg中找到相应的消息。更好的代码用于创建对象并从XML更新其属性

我在.NET 4.0中有下面的C#代码。它工作正常,合理可读。有没有更好的代码performance而不牺牲readability

CODE

// Create a collection of invoice elements 
var invoiceEntities = xDoc.Descendants("Invoice") 
       .Select(x => new Invoice 
       { 
        Vendor = x.Element("Vendor") == null ? String.Empty : x.Element("Vendor").Value.Trim(), 
        Amount = x.Element("Amount") == null ? String.Empty : x.Element("Amount").Value.Trim() 
       }); 

List<Invoice> invoices = invoiceEntities.ToList(); 

//Iterate all entities for finding corresponding message element and update the entity's Message 

int count = 0; 
foreach (Invoice entity in invoices) 
{ 
      count++; 

      //Dynamic XPath statement 
      string messagePath = @"Status/StatusMsg/StatusDetail/Sequence[text()=" + count.ToString() + "]/../Message"; 
      var statusDetails = xDoc.XPathSelectElements(messagePath).FirstOrDefault(); 
      if (statusDetails != null) 
      { 
       entity.Message = statusDetails.Value; 
       entity.Sequence = count; 
      } 

    } 

实体

public class Invoice 
{ 
    public string Vendor { get; set; } 
    public string Amount { get; set; } 
    public string Message { get; set; } 
    public int Sequence { get; set; } 
} 

XML

XDocument xDoc = XDocument.Parse(@" 
      <Status> 
       <StatusMsg> 
        <StatusType>INVOICE</StatusType> 
        <StatusCode>READYPAY</StatusCode> 
        <StatusTimestamp>2013-03-19T21:20:54Z</StatusTimestamp> 

        <StatusDetail> 
         <Sequence test=""K""> 2 </Sequence> 
         <Message>STL MESSAGE </Message> 
        </StatusDetail> 

        <StatusDetail> 
         <Sequence test=""1""> 1 </Sequence> 
         <Message>AKP MESSAGE</Message> 
        </StatusDetail> 

        <StatusDetail> 
         <Sequence> 1 </Sequence> 
         <Message>CC</Message> 
        </StatusDetail> 

       </StatusMsg> 
       <Invoices> 

        <Invoice> 
         <Vendor> 
         AKP LLC 
         </Vendor> 
         <Amount> 
         100 
         </Amount> 
        </Invoice> 

        <Invoice> 
         <Vendor> 
         STL Inc 
         </Vendor> 
         <Amount> 
         20950 
         </Amount> 
        </Invoice> 

       </Invoices> 
      </Status> 
      "); 

参考

  1. Generate c# object code and assign values to its properties from an xml document
  2. Use Annotations to Transform LINQ to XML Trees in an XSLT Style - Eric White
  3. Advantages of XSLT or Linq to XML
+2

考虑'XmlSerializer.Deserialize()'。 MSDN链接 - http://msdn.microsoft.com/en-gb/library/tz8csy73.aspx – LukeHennerley 2013-03-20 12:36:14

+1

除非他可以重新构造XML,反序列化不会做他那么好。除发票序列外,他在StatusDetail和Invoice之间没有定义的链接,这似乎相当浮躁。如果您有选择,我建议重新构建。当然,你可以对它进行反序列化,然后使用发票列表索引对个别StatusDetail条目的序列进行...但是,对于很少的收益(如果有的话)来说,这似乎有很多工作。更多的内存密集以及.... – Nevyn 2013-03-20 13:09:45

回答

1

关于我真的可以推荐的唯一事情就是到StatusDetail节点存储在一个列表为好,只要抓住了一大堆人一次,那么你可以通过第二个linq语句来引用列表来过滤序列。最后,这可能比简单构建和重新使用XPath字符串更慢。

var Details = xDoc.Descendants("StatusDetail").ToList(); 

... 

var statusDetail = Details.Where(a => a.Sequence == count).FirstOrDefault(); 

为挑剔的发展来看,其通常建议做奇怪的concantenated串那样的......一些关于反码更有效率时使用String.Format ...

string messagePath = String.Format("Status/StatusMsg/StatusDetail/Sequence[text()={0}]/../Message", count); 

另一种选择,您已经构建了一个匿名类型,但没有真正的理由您无法在“发票”选项中进行计数。这至少可以使您不必在循环中单独声明和维护计数。

int count = 1; 

var invoiceEntities = xDoc.Descendants("Invoice") 
      .Select(x => new Invoice 
      { 
       Vendor = x.Element("Vendor") == null ? String.Empty : x.Element("Vendor").Value.Trim(), 
       Amount = x.Element("Vendor") == null ? String.Empty : x.Element("Amount").Value.Trim(), 
       Index = count++ 
      });//yes that works, I tested it because even I wasn't sure, but Index is correct and different for each element 
相关问题