1

I have problem with building object holding XML data using Linq. For example, I have XML data in url http://api.eve-central.com/api/marketstat?typeid=34&usesystem=30000142 . In MarketStat class I want to hold type id value and in MarketValue class array I want to hold volume avg max min stddev median percentilevalues of buy sell all nodes. I have never used linq so far so please help me fix my problem in code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    internal class MarketValue
    {
        public int Volume { get; set; }
        public double Avg { get; set; }
        public double Max { get; set; }
        public double Min { get; set; }
        public double Stddev { get; set; }
        public double Median { get; set; }
        public double Percentile { get; set; }
    }
    internal class MarketStat
    {
        public string Name { get; set; }
        public MarketValue[] MarketValueses { get; set; }
    }
    internal class Program
    {
        private static List<MarketStat> list;
        internal static void Main(string[] args)
        {
            list = (
                from e in XDocument.Load("http://api.eve-central.com/api/marketstat?typeid=34&usesystem=30000142").
                    Root.Elements("marketstat")
                select new MarketStat
                {
                    Name = (string) e.Element("type id"),
                    MarketValueses = (
                        from mv in e.Elements("buy")
                        select new MarketValue
                        {
                            Volume = (int) mv.Element("volume"),
                            Avg = (double) mv.Element("avg"),
                            Max = (double)mv.Element("max"),
                            Min = (double)mv.Element("min"),
                            Stddev = (double)mv.Element("stddev"),
                            Median = (double)mv.Element("median"),
                            Percentile = (double)mv.Element("percentile")
                        }).ToArray()
               }).ToList();
         }
    }
}
  • Your link only brings back a set of numbers, not any XML. Maybe this QA can help you: http://stackoverflow.com/questions/10518372/how-to-deserialize-xml-to-object – John Feb 08 '16 at 16:18
  • 1
    @John, it returns XML; probably your browser just treated it as HTML rather than displaying it raw. – adv12 Feb 08 '16 at 16:20
  • Ok duly noted. I think the QA mentioned will help to serialize the object. – John Feb 08 '16 at 16:23

3 Answers3

2

The problem with your current code is that you want to fetch the id attribute of type element but you are trying to fetch it with type id which is wrong. Also you have the values of MarketValue in three nodes i.e. buy,sell & all but currently you are fetching details from just buy node.

This should give you the expected output:-

XDocument xdoc = XDocument.Load("http://api.eve-central.c...
var result = xdoc.Root.Elements("type")
                 .Select(ms => new MarketStat
                    {
                        Name = (string)ms.Attribute("id"),
                        MarketValueses = ms.Elements()
                                      .Select(mv => new MarketValue
                                         {
                                             Volume = (long)mv.Element("volume"),
                                             Avg = (double)mv.Element("avg"),
                                             Max = (double)mv.Element("max"),
                                             Min = (double)mv.Element("min"),
                                             Stddev = (double)mv.Element("stddev"),
                                             Median = (double)mv.Element("median"),
                                             Percentile = (double)mv.Element("percentile")
                                         }).ToArray()
                             }).ToList();
Rahul Singh
  • 21,585
  • 6
  • 41
  • 56
  • Code give me an error of empty `result` list. When I'm using `Root.Elements("marketstat").Select(ms => new MarketStat` with `Name = (string) ms.Element("type").Attribute("id")` its working for `type id` node but array which should hold `buy` `sell` `all` give me an error. Please check the code again for me. –  Feb 09 '16 at 09:31
  • @user5671675 - Yeah that's because now you have `evec_api` as the root node so this line is failing `xdoc.Root.Elements("type")`. In order to traverse through the XML you need to tell `type` node is present inside `marketstat` node, so your code should be :- `xdoc.Root.Element("marketstat").Elements("type")` _Or Else_ you can directly fetch all the _type_ nodes like this:- `xdoc.Descendants("type").Select...` – Rahul Singh Feb 09 '16 at 09:54
  • 1
    Thank you. Now I see where is my problem, with working code I will keep doing exercises and skill up with XML Documents. –  Feb 09 '16 at 12:50
1

You're looking for an element called "type id". That's not a valid name for an element in XML. You should just look for elements called type... that's the name of this element:

<type id="34">

If you want to filter by ID, you could then fetch the attribute id.

You're also trying to fetch the buy element directly from the marketstat element - it isn't there; it's within the type element. You need to pay more attention to the structure of the XML, basically.

My guess is that you should only expect a single buy element, too - which makes things simpler. I suspect you don't need an array within each element of your results...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

You have a few things wrong with your xml parsing.

first of all you can't call type id as you do here

Name = (string) e.Element("type id")

id is an attribute of the type element so you would have to do something like this

Name = e.Element("type").Attributes("id").Value

Another issue is in the section where you are trying to iterate the buy values. you have the following line

from mv in e.Elements("buy")

This will not work because e is the document root element. buy is a child of the type element so you would want something like this

from mv in e.Elements("type").Descendants("buy")

Hope this helps and points you in the right direction

Here is a working example

list = (
    from e in XDocument.Load("http://api.eve-central.com/api/marketstat?typeid=34&usesystem=30000142").
        Root.Elements("marketstat")
        let type = e.Element("type")
    select new MarketStat
    {
        Name = type.Attribute("id").Value,
        MarketValueses = (
            from mv in type.Descendants("buy")
            select new MarketValue
            {
                Volume = long.Parse(mv.Element("volume").Value),
                Avg = double.Parse(mv.Element("avg").Value),
                Max = double.Parse(mv.Element("max").Value),
                Min = double.Parse(mv.Element("min").Value),
                Stddev = double.Parse(mv.Element("stddev").Value),
                Median = double.Parse(mv.Element("median").Value),
                Percentile = double.Parse(mv.Element("percentile").Value)
            }).ToArray()
    }).ToList();

** On a side note, when parsing that xml, the volume value was too large to fit into an int32 value so I changed it to a long

hawkstrider
  • 4,141
  • 16
  • 27