如何使用 linq to xml 获取元素值并将其分配给 Double?

How to get element value and assign it to a Double using linq to xml?

我需要从下面的 xml 中获取所有 3 个 "avg" 值的值,然后将它们分配给一个双精度数组。使用 linq 到 xml。我是 linq to xml 的新手,所以我不太确定该怎么做。

这是我当前的代码

var q = from e in xDoc.Descendants("sell")
        select new
        {
            result = e.Element("avg").Value
        };

XML:

<?xml version='1.0' encoding='utf-8'?>
<evec_api version="2.0" method="marketstat_xml">
    <marketstat>
        <type id="626">
            <buy>
                <volume>11</volume>
                <avg>9345454.55</avg>
                <max>11500000.00</max>
                <min>7500000.00</min>
                <stddev>1862495.34</stddev>
                <median>7600000.00</median>
                <percentile>11500000.00</percentile>
            </buy>
            <sell>
                <volume>23</volume>
                <avg>18749987.25</avg>
                <max>18749987.25</max>
                <min>18749987.25</min>
                <stddev>0.00</stddev>
                <median>18749987.25</median>
                <percentile>18749987.25</percentile>
            </sell>
            <all>
                <volume>34</volume>
                <avg>15707344.32</avg>
                <max>18749987.25</max>
                <min>7500000.00</min>
                <stddev>4573474.77</stddev>
                <median>18749987.25</median>
                <percentile>7500000.00</percentile>
            </all>
        </type>
    </marketstat>
</evec_api>
using System;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            var xml = @"<?xml version='1.0' encoding='utf-8'?>
<evec_api version=""2.0"" method=""marketstat_xml"">
    <marketstat>
        <type id=""626"">
            <buy>
                <volume>11</volume>
                <avg>9345454.55</avg>
                <max>11500000.00</max>
                <min>7500000.00</min>
                <stddev>1862495.34</stddev>
                <median>7600000.00</median>
                <percentile>11500000.00</percentile>
            </buy>
            <sell>
                <volume>23</volume>
                <avg>18749987.25</avg>
                <max>18749987.25</max>
                <min>18749987.25</min>
                <stddev>0.00</stddev>
                <median>18749987.25</median>
                <percentile>18749987.25</percentile>
            </sell>
            <all>
                <volume>34</volume>
                <avg>15707344.32</avg>
                <max>18749987.25</max>
                <min>7500000.00</min>
                <stddev>4573474.77</stddev>
                <median>18749987.25</median>
                <percentile>7500000.00</percentile>
            </all>
        </type>
    </marketstat>
</evec_api>";

            var xdoc = XDocument.Parse(xml);
            var typeElement = xdoc.Element("evec_api").Element("marketstat").Element("type");
            var avgElements = typeElement.Elements().Select(e => e.Element("avg"));

            foreach (var avgElement in avgElements)
                Console.WriteLine(avgElement.Value);
        }
    }
}

上面代码的问题是您只检索 avg 之一的值。使用 Descendants 你可以找到所有的 avg 然后得到值:

var result = xDoc.Descendants("avg").Select(e => (double)e);

如果你想确定它是 double 而不是失败和 InvalidCast 然后使用 double.TryParse: 记住这有一个副作用使用了value。如果你不想这样做,你可以在 where 中使用 TryParse,然后在 select

中再次使用 Parse
double value = 0;
var result = (from element in xDoc.Descendants("avg")
              where double.TryParse(element.Value, out value)
              select value).ToList();

// result: 9345454.55, 18749987.25, 15707344.32

如果您希望结果在数字和来源之间也有一些暗杀,您可以使用 .Parent 属性:

double value = 0;
var result = (from element in xDoc.Descendants("avg")
              where  double.TryParse(element.Value, out value)
              select new
              {
                  Tag = element.Parent.Name.LocalName,
                  Value = value
              }).ToList();

这些答案看起来非常冗长。如果您想要三个 avg 值,并且只有来自标签 <marketstat><type id="626"> 的值,但是如果您想要避免更多的市场统计和类型,则必须深入挖掘。

double[] averages = xDoc.Descendants("avg")
                        .Select(xavg => (double)xavg)
                        .ToArray();

例如,

XElement type626 = xDoc.Descendants("type")
                       .First(x => (int)x.Attribute("id") == 626);

然后将前面的粘贴到这里,我们将 xDoc 替换为 type626

double[] averages = type626.Descendants("avg")
                        .Select(xavg => (double)xavg)
                        .ToArray();

在 VB.Net 中我会做

    Dim avgs() As Double = xe...<avg>.Select(Function(a) CDbl(a.Value)).ToArray

在 C# 中看起来像这样(根据我使用的转换器)

double[] avgs = xe.Select(a => Convert.ToDouble(a.Value)).ToArray;

测试

    Dim xe As XElement
    'to load from a file
    '  xe = XElement.Load("Your Path Here")

    ' for testing
    xe = <evec_api version="2.0" method="marketstat_xml">
             <marketstat>
                 <type id="626">
                     <buy>
                         <volume>11</volume>
                         <avg>9345454.55</avg>
                         <max>11500000.00</max>
                         <min>7500000.00</min>
                         <stddev>1862495.34</stddev>
                         <median>7600000.00</median>
                         <percentile>11500000.00</percentile>
                     </buy>
                     <sell>
                         <volume>23</volume>
                         <avg>18749987.25</avg>
                         <max>18749987.25</max>
                         <min>18749987.25</min>
                         <stddev>0.00</stddev>
                         <median>18749987.25</median>
                         <percentile>18749987.25</percentile>
                     </sell>
                     <all>
                         <volume>34</volume>
                         <avg>15707344.32</avg>
                         <max>18749987.25</max>
                         <min>7500000.00</min>
                         <stddev>4573474.77</stddev>
                         <median>18749987.25</median>
                         <percentile>7500000.00</percentile>
                     </all>
                 </type>
             </marketstat>
         </evec_api>