How can I group/sum values in LINQ to XML?

回眸只為那壹抹淺笑 提交于 2021-02-10 14:23:04

问题


I've been trying to work thru this but I am having problems grouping the data. I have an XML structure

<FILE>
    <PLAN>
      <PLAN_ID>001</PLAN_ID>
      <PARTICIPANT>
        <PARTICIPANT_ID>9999</PARTICIPANT_ID>
        <INVESTMENTS>
          <INVESTMENT>
            <INVESTMENT_ID>ABC</INVESTMENT_ID>
            <BALANCE>1000</BALANCE>
            <ELECTION>0.00</ELECTION>
          </INVESTMENT>
          <INVESTMENT>
            <INVESTMENT_ID>XYZ</INVESTMENT_ID>
            <BALANCE>2000</BALANCE>
            <ELECTION>0.00</ELECTION>
          </INVESTMENT>
          <INVESTMENT>
            <INVESTMENT_ID>QWERTY</INVESTMENT_ID>
            <BALANCE>3000</BALANCE>
            <ELECTION>100.0</ELECTION>
          </INVESTMENT>
        </INVESTMENTS>
      </PARTICIPANT>
    </PLAN>
    <PLAN>
      <PLAN_ID>002</PLAN_ID>
      <PARTICIPANT>
        <PARTICIPANT_ID>9999</PARTICIPANT_ID>
        <INVESTMENTS>
          <INVESTMENT>
            <INVESTMENT_ID>ABC</INVESTMENT_ID>
            <BALANCE>2000</BALANCE>
            <ELECTION>0.00</ELECTION>
          </INVESTMENT>
          <INVESTMENT>
            <INVESTMENT_ID>XYZ</INVESTMENT_ID>
            <BALANCE>4000</BALANCE>
            <ELECTION>0.00</ELECTION>
          </INVESTMENT>
          <INVESTMENT>
            <INVESTMENT_ID>QWERTY</INVESTMENT_ID>
            <BALANCE>6000</BALANCE>
            <ELECTION>100.0</ELECTION>
          </INVESTMENT>
        </INVESTMENTS>
      </PARTICIPANT>
    </PLAN>
</FILE>

I started with just trying to get the SUM of all of the BALANCE elements

var doc = XDocument.Load("test.xml");

var sum = (from nd in doc.Descendants("BALANCE")
           select Int32.Parse(nd.Value)).Sum();

Console.WriteLine(sum);

and that worked, giving me 18000. Then I wanted to group the data by the PLAN_ID but I cannot get it to give me other than 0.

var doc = XDocument.Load("test.xml");
var q = from x in doc.Descendants("PLAN")
        group x by x.Element("PLAN_ID").Value into gr
        select new
        {
             key = gr.Key,
             tot = (from tx in gr.Elements("BALANCE")
                    select (int)tx).Sum()
        };

When I run that I get:

  • [0] { key = "001", tot = 0 }
  • [1] { key = "002", tot = 0 }

Where did I go wrong?


回答1:


The problem is that you're using Elements() when the element you're looking for is deeper into the XML tree than a single level. If you switch to Descendants() within your inner query, then you should get the results you're expecting.

var doc = XDocument.Load("test.xml");
var q = from x in doc.Descendants("PLAN")
        group x by x.Element("PLAN_ID").Value into gr
        select new
        {
             key = gr.Key,
             tot = (from tx in gr.Descendants("BALANCE")
                    select (int)tx).Sum()
        };

The BALANCE nodes are 3 nodes deeper than the inner nodes of each PLAN node, so this should do the trick.

Personally, I like using the lambda version because it's a bit cleaner, so just for completeness here's the associated solution using the lambda syntax:

var q = doc.Descedants("PLAN")
         .GroupBy(x => x.Element("PLAN_ID").Value))
         .Select(gr => new 
         {
             key = gr.Key,
             tot = gr.Sum(tx => (int)tx.Descendants("BALANCE"))
         });


来源:https://stackoverflow.com/questions/44935652/how-can-i-group-sum-values-in-linq-to-xml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!