简体   繁体   English

使用C#的LINQ和XML

[英]LINQ and XML with C#

<root>
    <level1 name="A">
        <level2 name="A1" />
        <level2 name="A2" />
    </level1>
    <level1 name="B">
        <level2 name="B1" />
        <level2 name="B2" />
    </level1>
    <level1 name="C" />
</root>

Could someone give me a C# code using LINQ, the simplest way to print this result: (Note the extra space if it is a level2 node) 有人可以使用LINQ给我一个C#代码,这是打印此结果的最简单方法:(请注意,如果它是一个level2节点,则需要额外的空间)

A
  A1
  A2
B
  B1
  B2
C

XDocument xdoc = XDocument.Load("data.xml"));
var lv1s = from lv1 in xdoc.Descendants("level1")
           select lv1.Attribute("name").Value;

foreach (var lv1 in lv1s)
{
    result.AppendLine(lv1);

    var lv2s = from lv2 in xdoc...???
}
var xDoc = XDocument.Load(filename);
var lookup = xDoc.Descendants("param")
                 .ToLookup(x => x.Attribute("name").Value, x => (double)x);

foreach (var p in lookup)
{
    Console.WriteLine("{0,-12} {1,6:#0.0} {2,6:#0.0} {3,6:#0.0}", 
                        p.Key,  p.Min(),  p.Average(),  p.Max());
}

OUTPUT: 输出:

temperature     9.3   10.3   11.2
pH              3.0    6.3   10.0
Phosphate       4.0    4.0    4.0
Chloride        4.0    4.0    4.0
Nitrate        10.0   10.0   10.0

By using XPath, here's how you could do it for the average: 通过使用XPath,以下是您可以平均使用的方法:

float GetAvgTemperature(XmlDocument document)
{
    var temperatureNodes = document.SelectNodes("/samples/measurement/param[@name='temperature']");
    return temperatureNodes == null ? 0 : temperatureNodes.Cast<XmlNode>().Average(node => float.Parse(node.InnerText, CultureInfo.InvariantCulture));
}

You can easily make this function more generic to return either Minimum/Average/Maximum and for any parameter name. 您可以轻松地使此函数更通用,以返回“最小值/平均值/最大值”以及任何参数名称。

This approach uses the LINQ aggregation to build the calculations in a single line of code as you requested. 这种方法使用LINQ聚合根据您的要求在一行代码中构建计算。

var values = samples.Descendants(XName.Get("param"))
    .Select(n => new {
        Name = n.Attribute(XName.Get("name")).Value,
        Value = float.Parse(n.Value)
    })
    .GroupBy(a => a.Name)
    .Select(a => new {
        Name = a.Key,
        MaxValue = a.Max(g => g.Value),
        MinValue = a.Min(g => g.Value),
        AvgValue = a.Average(g => g.Value)
    })
    .ToArray();

I would avoid using Descendants("param") unless you are validating the document in another way. 除非您以另一种方式验证文档,否则我将避免使用Descendants("param") Otherwise, if the document's format changes it might result in some unexpected results. 否则,如果文档格式更改,可能会导致某些意外结果。

Here's what you want: 这就是您想要的:

from p in samples.Elements("samples").Elements("measurement").Elements("param")
group (double)p by (string)p.Attribute("name") into grp
select new
{
    ParameterName = grp.Key,
    Min = grp.Min(),
    Avg = grp.Average(),
    Max = grp.Max()
}

Note the chained of Elements() calls, which makes precisely selecting down into the document very trivial, and casting of the XAttribute and XElement directly to double and string to get their values. 请注意,链式的Elements()调用非常精确,这使得在文档中的选择非常简单,并将XAttributeXElement直接转换为doublestring即可得到它们的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM