如何根据特定条件对XML文件中的值求和
本文关键字:求和 文件 XML 何根 特定条件 | 更新日期: 2023-09-27 18:28:42
我需要根据一些条件对XML文件中的值进行汇总
我的XMl如下
<?xml version="1.0" encoding="utf-8"?>
<transactions>
<transcation ID="1">
<BankName>ABC</BankName>
<TemplatModel>CT1</TemplatModel>
<Date>12/12/2014</Date>
<Payeename>xyz</Payeename>
<Amount>200</Amount>
</transcation>
<transcation ID="2">
<BankName>EFG</BankName>
<TemplatModel>CT2</TemplatModel>
<Date>12/12/2014</Date>
<Payeename>xyz</Payeename>
<Amount>100</Amount>
</transcation>
<transcation ID="3">
<BankName>ABC</BankName>
<TemplatModel>CT1</TemplatModel>
<Date>10/12/2014</Date>
<Payeename>pqr</Payeename>
<Amount>400</Amount>
</transcation>
<transcation ID="4">
<BankName>EFG</BankName>
<TemplatModel>CT2</TemplatModel>
<Date>11/12/2014</Date>
<Payeename>asd</Payeename>
<Amount>300</Amount>
</transcation>
</transactions>
我需要找到BankName="ABC"的金额总和,在另一个查询中,我需要找到其日期小于"12/12/2014"的金额总和
还有一个疑问是哪种xml结构更适合
<transactions>
<transcation ID="1" BankName="ABC" TemplatModel="CT1" Date="12/12/2014" Payeename="asd" Amount="200"/>
<transcation ID="2" BankName="EFG" TemplatModel="CT2" Date="12/12/2014" Payeename="xyz" Amount="100"/>
<transcation ID="3" BankName="ABC" TemplatModel="CT1" Date="10/12/2014" Payeename="pqr" Amount="400"/>
<transcation ID="4" BankName="EFG" TemplatModel="CT2" Date="11/12/2014" Payeename="asd" Amount="300"/>
</transactions>
编辑的问题
将查询结果返回到List时出错
public static List<string> banksearch(string bankname, string sdate = null, string edate = null, string condition = null)
{
}
return transactions
.Where(t => t.BankName == bankname && t.Date == startdate)
.Select(t => new
{
TransactionID = t.TransactionID,
BankName = t.BankName,
TemplateModel = t.TemplateModel,
Date = t.Date,
PayeeName = t.PayeeName,
Amount = t.Amount
}).ToList();
我的错误是
Error 2 Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.List<string>'
我将提供一种稍微不同的方法。在你的问题中,你提到了两个问题,我可以看出你还需要其他问题。在这种情况下,我建议将XML解析为一个对象,并拥有一个可以查询的对象集合。
首先,保存事务数据的对象(类):
public class Transaction
{
public int TransactionID { get; set; }
public string BankName { get; set; }
public string TemplatModel {get; set; }
public DateTime Date { get; set; }
public string PayeeName { get; set; }
public decimal Amount { get; set; }
}
请注意,我选择了十进制来表示金额——这是货币单位的正常选择。
接下来,您可以使用LINQ to XML将XML解析为Transaction
对象的集合,如下所示(基于您的第一个XML),并假设您有一个名为xDoc
的XDocument
表示XML文件:
List<Transaction> transactions = xDoc.Root.Elements("transcation")
.Select(x => new Transaction() {
TransactionID = Convert.ToInt32((string)x.Attribute("ID")),
BankName = (string)x.Element("BankName"),
TemplatModel = (string)x.Element("TemplatModel"),
Date = Convert.ToDateTime((string)x.Element("Date")),
PayeeName = (string)x.Element("Payeename"),
Amount = Convert.ToDecimal((string)x.Element("Amount"))
}).ToList();
注意(string)
的使用-这将优雅地处理丢失的元素,而不会引发null引用异常。
最后,使用transactions
集合,您可以运行任何类型的查询,包括您在问题中提到的两个:
var banksByName = transactions.Where(t => t.BankName == "ABC")
和
DateTime selectedDate = new DateTime(2014, 12, 22);
var transByDate = transactions.Where(t => t.Date < selectedDate);
这种方法的优点是,您可以一次性查询XML以开发对象集合,然后根据需要随时查询该集合。
编辑以添加对新错误的修复
得到Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.List<string>'
错误的原因是您的方法期望返回List<string>
,而实际上返回的是List<AnonymousType>
。当您在没有具体类的LINQ Select语句中使用new
关键字时,您正在创建一个匿名类型,该类型不能在方法中返回。
要解决此问题,请将方法的返回类型更改为List<Transaction>
,并在new
关键字后添加Transaction
:
public static List<Transaction> banksearch(string bankname, string sdate = null, string edate = null, string condition = null)
{
return transactions.Where(t => t.BankName == bankname && t.Date == startdate)
.Select(t => new Transaction() {
TransactionID = t.TransactionID,
BankName = t.BankName,
TemplateModel = t.TemplateModel,
Date = t.Date,
PayeeName = t.PayeeName,
Amount = t.Amount
}).ToList();
您可以使用LINQ to XML实现以下功能:
DateTime exclusiveDateTime = new DateTime(2014, 12, 12);
// instantiate and load your XDocument as yourXDocument here
XElement transcationsElement = yourXDocument.Root;
IEnumerable<int> amounts = from transcation in transcationsElement.Descendants("transcation")
where transcation.Attribute("BankName").Value == "ABC" &&
Convert.ToDateTime(transcation.Attribute("Date").Value) < exclusiveDateTime
select Convert.ToDecimal(transcation.Attribute("amount"));
decimal amountsSum = amounts.Sum();
我使用您发布的第二个XML表单,因为我发现与元素的子元素相比,处理元素的相关属性更容易,但这主要是我个人的偏好。此解决方案假设您的每个Date和Amount属性分别正确地形成为DateTime字符串和int。如果不是这样的话,您将遇到InvalidCastExceptions。
请注意,如果您正在考虑扩展XML,并且需要对transcation
元素执行更多查询,那么您可能只需要创建一个类来封装每个元素中包含的数据,并使用LINQ to Objects来解析数据并实例化每个对象。
我将帮助您处理一个查询(金额总和)和另一个基于第一个查询的查询
int sum = 0;
transactionXml.Descendants("transaction").ToList().ForEach(i => {
if (String.Equals(i.Element("BankName").Value, "abc", StringComparison.OrdinalIgnoreCase))
sum += Convert.ToInt32(i.Element("Amount").Value);
});
关于XML结构,银行名称和收款人名称可能具有特殊字符,这些字符可能会破坏您的XML。因此,建议的XML结构如下
<transactions>
<transcation ID="1" TemplatModel="CT1" Date="12/12/2014" Amount="200">
<BankName>ABC</BankName>
<Payeename>asd</Payeename>
</transcation>
***
***
***
</transactions>