如何根据特定条件对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文件中的值求和

我将提供一种稍微不同的方法。在你的问题中,你提到了两个问题,我可以看出你还需要其他问题。在这种情况下,我建议将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),并假设您有一个名为xDocXDocument表示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>