在 LINQ 中分组到 XML 与 "any" 或第一个“聚合

Grouping in LINQ to XML with "any" or first" aggregation

我需要使用 LINQ to XML 或 XPath by param/Type 对 XML 进行分组。通过分组,我想获得 id 标签的任何(或首先,无关紧要)值。

<list>
<item>
    <id>1</id>
    <param>
        <type>A</type>
    </param>
</item>
<item>
    <id>2</id>
    <param>
        <type>A</type>
    </param>
</item>
<item>
    <id>3</id>
    <param>
        <type>B</type>
    </param>
</item>
<item>
    <id>4</id>
    <param>
        <type>B</type>
    </param>
</item>

理想的结果是

A - 1
B - 3

我试过了

var content = from item in doc.Descendants("item").Descendants("param")
group item by new
{
       mType = (String)item.Element("type"),                                                
} into g
select new
{
    mType = g.Key.mType,                              
}; 

但我不知道如何引用层次结构中较高的 ID,或者在选择 ID 时如何引用 PARAM/TYPE。

我建议 using System.Xml.Linq (XDocument)

如果我的理解不错,这是我所做的:

var xml = "<list><item><id>1</id><param><type>A</type></param></item><item><id>2</id><param><type>A</type></param></item><item><id>3</id><param><type>B</type></param></item><item><id>4</id><param><type>B</type></param></item></list>";
var document = XDocument.Parse(xml);

foreach (var param in document.Root.Elements("item").GroupBy(i => i.Element("param").Element("type").Value))
{
    var firstId = param.First().Element("id").Value;
    Console.WriteLine ("The first of {0} = {1}", param.Key, firstId);
}

输出是:

The first of A = 1
The first of B = 3

除了 Cedric 所建议的之外,您还可以在纯 XPath 中完成同样的事情:

var xml = "<list><item><id>1</id><param><type>A</type></param></item><item><id>2</id><param><type>A</type></param></item><item><id>3</id><param><type>B</type></param></item><item><id>4</id><param><type>B</type></param></item></list>";
var document = XDocument.Parse(xml);

// start at the root, then grab the first item element which has a param/type element whose value is equal to 'B'
var answer = document.Root.XPathSelectElement("./item[./param/type='B'][1]").Element("id").Value;

在 XPath 中,方括号的功能类似于 where 子句。我的第一组方括号表明我想要一个包含匹配 param/type 元素的项目。第二组方括号将其限制为第一场比赛。