你只是将细节汇总起来,或者实际上试图匹配完全相互抵消的细节?前者会更容易编写。
例如,为一个文件,看起来像这样
<Root>
<Details>
<Detail>
<Number>1</Number>
<Amount>40.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-20.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-30.0</Amount>
<RefNo>2</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
</Details>
</Root>
XDocument doc = ...;
var details = doc.XPathSelectElement("/Root/Details");
var newDetails =
from detail in details.Elements("Detail")
let amount = (decimal)detail.Element("Amount")
let number = (int)detail.Element("Number")
let refNo = (int)detail.Element("RefNo")
// group amounts by number and refno
group amount by new { number, refNo } into g
let amount = g.Sum()
// filter out completely canceled out groups
where amount != 0M
select new XElement("Detail",
new XElement("Number", g.Key.number),
new XElement("Amount", amount.ToString("N1")),
new XElement("RefNo", g.Key.refNo)
);
details.ReplaceAll(newDetails);
产量:
<Root>
<Details>
<Detail>
<Number>1</Number>
<Amount>60.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-30.0</Amount>
<RefNo>2</RefNo>
</Detail>
</Details>
</Root>
否则,你需要匹配的是相互抵消的元素。它仍然可以在单个查询中完成,但稍微复杂一点。
XDocument doc = ...;
var details = doc.XPathSelectElement("/Root/Details");
var newDetails =
from detail in details.Elements("Detail")
let amount = (decimal)detail.Element("Amount")
let number = (int)detail.Element("Number")
let refNo = (int)detail.Element("RefNo")
let key = Math.Abs(amount) // cancellable amounts
// group amounts by key, number and refno
group amount by new { key, number, refNo } into g
let amount = g.Sum()
// filter out completely canceled out groups
where amount != 0M
let count = (int)Math.Abs(amount/g.Key.key) // how many to recreate
let sign = Math.Sign(amount)
// recreate uncancelled values
from a in Enumerable.Repeat(sign * g.Key.key, count)
select new XElement("Detail",
new XElement("Number", g.Key.number),
new XElement("Amount", a.ToString("N1")),
new XElement("RefNo", g.Key.refNo)
);
details.ReplaceAll(newDetails);
产量:
<Root>
<Details>
<Detail>
<Number>1</Number>
<Amount>40.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-30.0</Amount>
<RefNo>2</RefNo>
</Detail>
</Details>
</Root>
感谢杰夫您的帮助 – 2014-10-19 02:01:37