C#删除重复的条目,并将删除的条目的值汇总到第一个

时间:2018-03-25 13:59:46

标签: c# xml linq

我的代码是删除重复的发票并将一些值加到主发票上,以便只保留一张具有相同哈希值的发票而不是更多相同的发票。

我的代码:

using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;

    namespace ConsoleApplication2
    {
        class Program
        {
            //File
            const string FILE = "ccc.xml";
            static void Main(string[] args)
            {
                XDocument doc = XDocument.Load(FILE);

                List <XElement> originalInvoices = doc.Descendants("Invoice").ToList();

                var groups = originalInvoices.GroupBy(x => (string)x.Element("Hash")).ToList();

                var finalInvoices = groups.Select(x => new {
                    unit = x.Descendants("UnitPrice").Sum(z => (decimal)z),
                    credit = x.Descendants("CreditAmount").Sum(z => (decimal)z),
                    tax = x.Descendants("TaxPayable").Sum(z => (decimal)z),
                    net = x.Descendants("NetTotal").Sum(z => (decimal)z),
                    gross = x.Descendants("GrossTotal").Sum(z => (decimal)z),
                    first = x.First()
                }).ToList();

                foreach (var finalInvoice in finalInvoices)
                {
                    finalInvoice.first.Element("Line").SetElementValue("UnitPrice", finalInvoice.unit);
                    finalInvoice.first.Element("Line").SetElementValue("CreditAmount", finalInvoice.credit);
                    finalInvoice.first.Element("DocumentTotals").SetElementValue("TaxPayable", finalInvoice.tax);
                    finalInvoice.first.Element("DocumentTotals").SetElementValue("NetTotal", finalInvoice.net);
                    finalInvoice.first.Element("DocumentTotals").SetElementValue("GrossTotal", finalInvoice.gross);
                }

                doc.Element("SalesInvoices").ReplaceWith(new XElement("SalesInvoices", finalInvoices.Select(x => x.first)));
                Console.WriteLine(doc);
                Console.ReadKey();

            }
        }
    }

问题是我的代码在最后到达下一行时会爆炸:

doc.Element("SalesInvoices").ReplaceWith(new XElement("SalesInvoices", finalInvoices.Select(x => x.first)));

错误:&#39; System.NullReferenceException&#39;但我不知道为什么它有空,因为我有发票,但是当我添加断点时,它没有找到任何重复的发票。

我无法解决此问题,我的文件就是这个:Pastebin XML File

基本上,代码应删除Invoices重复Hash并将UnitPrice,CreditAmount,TaxPayable,NetTotal和GrossTotal的值相加,其中UnitPrice和Credit必须与NetTotal相同。

因此,我没有多张具有相同哈希值的发票,而是只有一张具有上述值总和的哈希值。

代码已删除重复的代码并对值进行求和,但不知怎的,我不知道如何解决问题。

如果有人帮我解决问题,如何解析我的整个文件会很好,因为此刻它告诉我,当我拥有它们时我没有发票。

通过添加&#34; XNamespace n = doc.Root.Name.Namespace更新我的代码;&#34;:

XDocument doc = XDocument.Load(FILENAME);

    XNamespace n = doc.Root.Name.Namespace;


    List <XElement> originalInvoices = doc.Root.Descendants(n + "Invoice").ToList();

    var groups = originalInvoices.GroupBy(x => (string)x.Element(n + "Hash")).ToList();

    var finalInvoices = groups.Select(x => new {
        unit = x.Descendants(n + "UnitPrice").Sum(z => (decimal)z),
        credit = x.Descendants(n + "CreditAmount").Sum(z => (decimal)z),
        tax = x.Descendants(n + "TaxPayable").Sum(z => (decimal)z),
        net = x.Descendants(n + "NetTotal").Sum(z => (decimal)z),
        gross = x.Descendants(n + "GrossTotal").Sum(z => (decimal)z),
        first = x.First()
    }).ToList();

    foreach (var finalInvoice in finalInvoices)
    {
        finalInvoice.first.Element(n + "Line").SetElementValue("UnitPrice", finalInvoice.unit);
        finalInvoice.first.Element(n + "Line").SetElementValue("CreditAmount", finalInvoice.credit);
        finalInvoice.first.Element(n + "DocumentTotals").SetElementValue("TaxPayable", finalInvoice.tax);
        finalInvoice.first.Element(n + "DocumentTotals").SetElementValue("NetTotal", finalInvoice.net);
        finalInvoice.first.Element(n + "DocumentTotals").SetElementValue("GrossTotal", finalInvoice.gross);
    }

我仍然有相同的错误,但现在当我到达foreach时,值不为null,但在行doc.Element("SalesInvoices").ReplaceWith(new XElement("SalesInvoices", finalInvoices.Select(x => x.first)));

中仍然有相同的错误

2 个答案:

答案 0 :(得分:0)

替换

doc.Element("SalesInvoices").ReplaceWith(new XElement("SalesInvoices", finalInvoices.Select(x => x.first)));

通过

var firstOnes = finalInvoices.Select(x => x.first);
var xElement = new XElement("SalesInvoices", firstOnes);
var salInv = doc.Element("SalesInvoices");
salInv.ReplaceWith(xElement);

并在第一个语句上设置断点。然后单步执行并了解正在发生的事情。或者只是运行,看看在哪里得到null。

顺便说一句:如果我没有完全弄错,“群组”是IGrouping&lt;字符串,XElement&gt;,所以如果你 - 在得到“groups”之后的下一行 - 从这个列表中选择一个x,它又是一个没有后代的IGrouping。对于后者,它必须是一个XElement,对吧?

答案 1 :(得分:0)

The is two issues with your code 1) Namespaces are needed 2) SalaesInvoices is not an element of doc but a descendant

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        //File
        const string FILE = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILE);
            XElement AuditFile = doc.Root;
            XNamespace ns = AuditFile.GetDefaultNamespace();

            List<XElement> originalInvoices = doc.Descendants(ns + "Invoice").ToList();

            var groups = originalInvoices.GroupBy(x => (string)x.Element(ns + "Hash")).ToList();

            var finalInvoices = groups.Select(x => new
            {
                unit = x.Descendants(ns + "UnitPrice").Sum(z => (decimal)z),
                credit = x.Descendants(ns + "CreditAmount").Sum(z => (decimal)z),
                tax = x.Descendants(ns + "TaxPayable").Sum(z => (decimal)z),
                net = x.Descendants(ns + "NetTotal").Sum(z => (decimal)z),
                gross = x.Descendants(ns + "GrossTotal").Sum(z => (decimal)z),
                first = x.First()
            }).ToList();

            foreach (var finalInvoice in finalInvoices)
            {
                finalInvoice.first.Element(ns + "Line").SetElementValue(ns + "UnitPrice", finalInvoice.unit);
                finalInvoice.first.Element(ns + "Line").SetElementValue(ns + "CreditAmount", finalInvoice.credit);
                finalInvoice.first.Element(ns + "DocumentTotals").SetElementValue(ns + "TaxPayable", finalInvoice.tax);
                finalInvoice.first.Element(ns + "DocumentTotals").SetElementValue(ns +"NetTotal", finalInvoice.net);
                finalInvoice.first.Element(ns + "DocumentTotals").SetElementValue(ns + "GrossTotal", finalInvoice.gross);
            }

            doc.Descendants(ns + "SalesInvoices").FirstOrDefault().ReplaceWith(new XElement("SalesInvoices", finalInvoices.Select(x => x.first)));
            Console.WriteLine(doc);
            Console.ReadKey();

        }
    }
}