2013-03-20 94 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 
相關問題