你只是將細節彙總起來,或者實際上試圖匹配完全相互抵消的細節?前者會更容易編寫。
例如,爲一個文件,看起來像這樣
<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