我有多个Invoice元素的XML输入。我从这些元素创建发票对象。根据发票元素的位置,我们需要分配序列号并从不同的元素中找到相应的消息 - StatusMsg。
我在.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>
");
参考:
答案 0 :(得分:1)
关于我唯一真正建议的是将StatusDetail
节点存储在List中,只需抓取它们一次,然后你可以通过第二个linq语句引用列表来过滤序列。这可能比简单地构建和重用XPath字符串更慢。
var Details = xDoc.Descendants("StatusDetail").ToList();
...
var statusDetail = Details.Where(a => a.Sequence == count).FirstOrDefault();
作为一个挑剔的开发点,它通常建议在做奇怪的连字符串时使用String.Format
......关于后端代码的效率更高......
string messagePath = String.Format("Status/StatusMsg/StatusDetail/Sequence[text()={0}]/../Message", count);
另一种选择,您已经在构建一个匿名类型,没有真正的理由不能将计数构建到Invoice选项中。这至少可以使您免于在循环中单独声明和维护计数。
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