如何使用LINQ将XML数据与以下结构进行分组和求和?

时间:2017-05-04 21:44:50

标签: c# xml linq sum grouping

XML结构:

<Root>
    <Place name="Place 1">
        <Event type="Type 1">
            <Title>Lorem ipsum dolor sit amet</Title>
            <Description>Lorem ipsum</Description>
            <People>73</People>
        </Event>

        <Event type="Type 2">
            <Title>Lorem ipsum dolor sit amet</Title>
            <Description>Lorem ipsum</Description>
            <People>3</People>
        </Event>
    </Place>

    <Place name="Place 2">
        <Event type="Type 1">
            <Title>Lorem ipsum dolor sit amet</Title>
            <Description>Lorem ipsum</Description>
            <People>10</People>
        </Event>

        <Event type="Type 2">
            <Title>Lorem ipsum dolor sit amet</Title>
            <Description>Lorem ipsum</Description>
            <People>49</People>
        </Event>
    </Place>
</Root>

我需要在所有地方对事件类型进行分组,并获得每种事件类型的总人数。我能想到的就是:

var event_types = from event in data.Elements("Event").Attributes("type")
                  group event by event.Value into g
                  select g;

但这只是分组,我完全不知道如何在尝试几个小时后获得总和。

结果应如下所示:

+------------+--------+
| Type       | People |
+------------+--------+
| Type 1     |     83 |
| Type 2     |     52 |
+------------+--------+

2 个答案:

答案 0 :(得分:3)

你可以试试这个:

var events=document.Descendants("Event")
                   .GroupBy(e=>(string)e.Attribute("type"))
                   .Select(g=>new {Type=g.Key, People=g.Sum(e=>(int)e.Element("People"))})

答案 1 :(得分:2)

以下是我将如何做到这一点:

var events = data.Root.Elements("Place")
    .SelectMany(p => p.Elements("Event"))
    .GroupBy(e => (string)e.Attribute("type"))
    .Select(g => new {
        Type = g.Key,
        People = g.Sum(e => Convert.ToInt32(e.Element("People").Value))
    });

将其分解,我们首先找到所有Event个节点:

.SelectMany(p => p.Elements("Event")) 
// returns an IEnumerable<XElement> of your four Events

然后我们按属性值进行分组:

.GroupBy(e => (string)e.Attribute("type"))
// returns an IEnumerable<IGrouping<string, XElement>> of two groups

最后,我们通过选择一个新的匿名类型来创建结果,其中Type属性是组键,People属性是子People元素中值的总和(首先转换为int):

.Select(g => new {
    Type = g.Key, // "Type 1" or "Type 2"
    People = g.Sum(e => Convert.ToInt32(e.Element("People").Value))
});
// g is the IGrouping<string, XElement>. You can use the LINQ method
// Sum across each XElement (e), e being your Event.

输出正如您所料:

+------------+--------+
| Type       | People |
+------------+--------+
| Type 1     |     83 |
| Type 2     |     52 |
+------------+--------+

编辑:如另一个答案所示,.GroupBy之前的行可以替换为data.Descendants("Event") - 我忽略了这条捷径。