使用C#Linq对嵌套对象进行分组和收集



愉快的编码。我可以用linq进行分组和求和,但这有点不同。我想把元素分组,然后一个接一个地收集起来。我想按TaxTypeCode分组并收集TaxAmount值。对不起,问题太长了。

我的xml

<Note>
<NoteLine>
<cbc:ID>1</cbc:ID>
<Quantity unitCode="C62">1.0000</Quantity>
<TaxTotal>
<cbc:TaxAmount currencyID="USD">201.00</cbc:TaxAmount>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">100.00</cbc:TaxAmount>
<cbc:Percent>25.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>0003</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">50.00</cbc:TaxAmount>
<cbc:Percent>10.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>9040</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">1.00</cbc:TaxAmount>
<cbc:Percent>1.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>0001</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">50.00</cbc:TaxAmount>
<cbc:Percent>10.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>8001</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
</TaxTotal>
</NoteLine>
<NoteLine>
<cbc:ID>2</cbc:ID>
<Quantity unitCode="C62">1.0000</Quantity>
<TaxTotal>
<cbc:TaxAmount currencyID="USD">460.00</cbc:TaxAmount>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">200.00</cbc:TaxAmount>
<cbc:Percent>20.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>0003</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">100.00</cbc:TaxAmount>
<cbc:Percent>10.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>9040</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">100.00</cbc:TaxAmount>
<cbc:Percent>10.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>8001</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">600.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">60.00</cbc:TaxAmount>
<cbc:Percent>10.00</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>8001</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
</TaxTotal>
</NoteLine> 
</Note>

那我们需要这样的东西。合计税额、应纳税额、税额。我认为这是可能的,但我该怎么做呢?

结果我想要

<TaxTotal>
<TaxAmount currencyID="USD">661.00</TaxAmount>
<TaxSubtotal>
<TaxableAmount currencyID="USD">1500.00</TaxableAmount>
<TaxAmount currencyID="USD">300.00</TaxAmount>
<Percent>25.00</Percent>
<TaxCategory>
<TaxScheme>
<TaxTypeCode>0003</TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
...
...
...
...
</TaxTotal>

我有一个用于序列化xml的创建示例类。

using (StreamReader reader = new StreamReader(@"C:Userstest.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(Note));
Note obj = (Note)serializer.Deserialize(reader);
}

但我还是做不到。

请尝试以下操作。这是可能的。保留了所有命名空间。诀窍是使用First((方法创建一个模板

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:temptest.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement note = doc.Descendants().Where(x => x.Name.LocalName == "Note").FirstOrDefault();
XNamespace nsCbc = note.GetNamespaceOfPrefix("cbc");
XNamespace ns = note.GetDefaultNamespace();
foreach (XElement taxTotal in note.Descendants(ns + "TaxTotal"))
{
var groups = taxTotal.Elements(ns + "TaxSubtotal").GroupBy(x => (string)x.Descendants(nsCbc + "TaxTypeCode").First()).Select(x => new {
template = x.First(),
taxAmount = x.Descendants(nsCbc + "TaxableAmount").Sum(z => (decimal)z),
tax = x.Descendants(nsCbc + "TaxAmount").Sum(z => (decimal)z)
}).ToList();
foreach (var group in groups)
{
group.template.SetElementValue(nsCbc + "TaxableAmount", group.taxAmount);
group.template.SetElementValue(nsCbc + "TaxAmount", group.tax);
group.template.SetElementValue(nsCbc + "Percent", 100 * (group.tax / group.taxAmount));
}
List<XElement> newSubtotals = groups.Select(x => new XElement(x.template)).ToList();
taxTotal.Elements(ns + "TaxSubtotal").Remove();
taxTotal.Add(newSubtotals);
}

}
}
}

他是输出XML

<?xml version="1.0" encoding="utf-8"?>
<Note xmlns:cbc="abc">
<NoteLine>
<cbc:ID>1</cbc:ID>
<Quantity unitCode="C62">1.0000</Quantity>
<TaxTotal>
<cbc:TaxAmount currencyID="USD">201.00</cbc:TaxAmount>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">100.00</cbc:TaxAmount>
<cbc:Percent>20.0</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>0003</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">50.00</cbc:TaxAmount>
<cbc:Percent>10.0</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>9040</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">1.00</cbc:TaxAmount>
<cbc:Percent>0.200</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>0001</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">500.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">50.00</cbc:TaxAmount>
<cbc:Percent>10.0</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>8001</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
</TaxTotal>
</NoteLine>
<NoteLine>
<cbc:ID>2</cbc:ID>
<Quantity unitCode="C62">1.0000</Quantity>
<TaxTotal>
<cbc:TaxAmount currencyID="USD">460.00</cbc:TaxAmount>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">200.00</cbc:TaxAmount>
<cbc:Percent>20.0</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>0003</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">1000.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">100.00</cbc:TaxAmount>
<cbc:Percent>10.0</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>9040</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
<TaxSubtotal>
<cbc:TaxableAmount currencyID="USD">1600.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="USD">160.00</cbc:TaxAmount>
<cbc:Percent>10.0</cbc:Percent>
<TaxCategory>
<TaxScheme>
<cbc:TaxTypeCode>8001</cbc:TaxTypeCode>
</TaxScheme>
</TaxCategory>
</TaxSubtotal>
</TaxTotal>
</NoteLine>
</Note>

@jdweng谢谢大家,你们的评论指导了我。

我在你的帮助下解决了这个问题。

XmlSerializer serializer = new XmlSerializer(typeof(Note));
Note obj = (Note)serializer.Deserialize(reader);

var Taxes = obj.NoteLine.SelectMany(rd => rd.TaxTotal.TaxSubtotal)
.GroupBy(tt => tt.TaxCategory.TaxScheme.TaxTypeCode).Select(cl => new
{
TaxableAmount = cl.Sum(x => x.TaxableAmount.Text),
TaxAmount = cl.Sum(x => x.TaxAmount.Text),
Tax = cl.First(),
cl.Key,
});
List<TaxSubtotal> TaxSubtotals = new List<TaxSubtotal>();
int i = 1;
foreach (var item in Taxes.ToList())
{
TaxSubtotals.Add(new TaxSubtotal()
{
Percent = item.Tax.Percent,
TaxableAmount = new TaxableAmount()
{
CurrencyID = "USD",
Text = item.TaxableAmount
},
TaxAmount = new TaxAmount()
{
CurrencyID = "USD",
Text = item.TaxAmount
},
TaxCategory = new TaxCategory()
{
TaxScheme = new TaxScheme()
{
Name = item.Tax.TaxCategory.TaxScheme.Name,
TaxTypeCode = item.Tax.TaxCategory.TaxScheme.TaxTypeCode
},
},
});
}
}

相关内容

  • 没有找到相关文章

最新更新