Deserializing XML where each object has a list of objects - c#

I'm working on a WP7 app which gets and updates data on a web server. If any updates need a response, I get a list of errors that needs to be dealt with, and a list of possible choices for each error. The issue I'm having is assigning each object its appropriate list of choices. As of now I get a list of errors, and another list of all possible choices for all errors. I'd like the error object to contain the list of only its options so I can handle that.
So here's an example response:
<?xml version="1.0" encoding="utf-8"?>
<response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<response_error_dialogs>
<error_dialog_list>
<error_dialog_choice>
<error_dialog_id>1301</error_dialog_id>
<error_dialog_message>You have changed the phone number. Select which phone number to make the primary contact number.</error_dialog_message>
<error_dialog_title>Phone Number Changed</error_dialog_title>
<error_dialog_is_set>false</error_dialog_is_set>
<error_dialog_choice_option_list>
<error_dialog_choice_option>
<error_dialog_choice_option_id>1</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Home</error_dialog_choice_option_title>
</error_dialog_choice_option>
<error_dialog_choice_option>
<error_dialog_choice_option_id>2</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Mobile</error_dialog_choice_option_title>
</error_dialog_choice_option>
<error_dialog_choice_option>
<error_dialog_choice_option_id>3</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Work</error_dialog_choice_option_title>
</error_dialog_choice_option>
</error_dialog_choice_option_list>
</error_dialog_choice>
<error_dialog_choice>
<error_dialog_id>1303</error_dialog_id>
<error_dialog_message>You have changed the account email address. Would you like this to be the new default email?</error_dialog_message>
<error_dialog_title>Email Address Changed</error_dialog_title>
<error_dialog_is_set>false</error_dialog_is_set>
<error_dialog_choice_option_list>
<error_dialog_choice_option>
<error_dialog_choice_option_id>1</error_dialog_choice_option_id>
<error_dialog_choice_option_title>No</error_dialog_choice_option_title>
</error_dialog_choice_option>
<error_dialog_choice_option>
<error_dialog_choice_option_id>2</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Yes</error_dialog_choice_option_title>
</error_dialog_choice_option>
</error_dialog_choice_option_list>
</error_dialog_choice>
</error_dialog_list>
</response_error_dialogs>
</response>
And here's the classes used:
public class ErrorDialog
{
XElement self;
public ErrorDialog() { }
public ErrorDialog(XElement errorDialog)
{
self = errorDialog;
}
public int errorDialogId
{
get { return (int)(self.Element("error_dialog_id")); }
}
public string errorDialogMessage
{
get { return (string)(self.Element("error_dialog_message")); }
}
public string errorDialogTitle
{
get { return (string)(self.Element("error_dialog_title")); }
}
public bool errorDialogIsSet
{
get { return (bool)(self.Element("error_dialog_is_set")); }
}
public List<ErrorDialogChoice> errorDialogChoice
{
get { return (List<ErrorDialogChoice>)(errorDialogChoice); }
}
public int errorDialogSelectedOption
{
get { return (int)(self.Element("error_dialog_selected_option")); }
}
}
class ErrorDialogChoice
{
XElement self;
public ErrorDialogChoice() { }
public ErrorDialogChoice(XElement errorDialogChoice)
{
self = errorDialogChoice;
}
public int errorDialogChoiceOptionId
{
get { return (int)(self.Element("error_dialog_choice_option_id")); }
}
public string errorDialogChoiceOptionTitle
{
get { return (string)(self.Element("error_dialog_choice_option_title")); }
}
}
And here's how I'm parsing it:
XElement response = XElement.Parse(data);
ErrorDialog[] dialogs = response
.Element("response_error_dialogs")
.Element("error_dialog_list")
.Elements("error_dialog_choice")
.Select(e => new ErrorDialog(e))
.ToArray();
ErrorDialogChoice[] edChoices = response
.Element("response_error_dialogs")
.Element("error_dialog_list")
.Element("error_dialog_choice")
.Element("error_dialog_choice_option_list")
.Elements("error_dialog_choice_option")
.Select(e => new ErrorDialogChoice(e))
.ToArray();
So with this example, the first error_dialog_choice object will have a List containing 3 error_dialog_choice_option objects, the second has the two error_dialog_choice_option objects, and any more that may come back. Any help is appreciated. Thanks.

You can use XML serialization to achieve this much easier:
var reader = new StringReader(xmlString);
var ser = new XmlSerializer(typeof(Response));
var result = (Response) ser.Deserialize(reader);
Using these class definitions.
[XmlType("response")]
public class Response
{
[XmlElement("response_error_dialogs")]
public ErrorDialog ErrorDialog;
}
[XmlType("response_error_dialogs")]
public class ErrorDialog
{
[XmlArray("error_dialog_list")]
public List<ChoiceErrorDialog> ChoiceList;
}
[XmlType("error_dialog_choice")]
public class ChoiceErrorDialog
{
[XmlElement("error_dialog_id")]
public int Id;
[XmlElement("error_dialog_message")]
public string Message;
[XmlElement("error_dialog_title")]
public string Title;
[XmlElement("error_dialog_is_set")]
public bool IsSet;
[XmlArray("error_dialog_choice_option_list")]
public List<Option> OptionList;
}
[XmlType("error_dialog_choice_option")]
public class Option
{
[XmlElement("error_dialog_choice_option_id")]
public int Id;
[XmlElement("error_dialog_choice_option_title")]
public string Title;
}
I am guessing there can be more types of error dialogs, and <error_dialog_choice> is just one of the possible types. In this case you could use subclassing, and list the subclasses with XmlArrayItem attributes.
You could also generate the class definitions with xsd.exe or svcutil.exe, from an .xsd or .wsdl file. xsd.exe can even infer the schema from a sample .xml file.
xsd.exe /?
svcutil.exe /?

Use the XmlSerializer built into the framework. Use attributes to map out the xml equivalent of your classes and their properties.
Example:
[XmlElement("Txn")]
public List<Transaction> Items { get; set; }
You can use the XSD.exe to generate an XSD and then generate C# code for your XSD. Use Visual Studio Command Prompt with a sample response.xml file. Eg:
c:>xsd response.xml
c:>xsd response.xsd /c /edb

Related

c# multi level json

I am trying to make a simple program that can automate price checking using data from json, however I haven't used json before and I'm not quite sure what I need to do get get the desired result.
Effectively I'm trying to convert this PHP into c#. (http://www.sourcecodester.com/tutorials/php/8042/api-json-parsing-php.html)
<?php
$src = file_get_contents('https://www.g2a.com/marketplace/product/auctions/?id=256');
$json = json_decode($src, true);
foreach ($json as $k=>$v) {
if (is_array($v)) {
foreach($v as $key=>$value) {
if (is_array($value)) {
foreach($value as $arKey => $arValue) {
if ($arKey == 'p') {
echo $arValue . '<br/>';
}
}
}
}
}
}
?>
I've tried a few things such as JsonConvert.DeserializeObject(webJson) and JObject.Parse(webJson), but I'm just not sure where I should be looking or how to go about doing it.
I have the first part:
internal static string GetWebContent(string #ID)
{
var wc = new WebClient();
string response = wc.DownloadString(#"https://www.g2a.com/marketplace/product/auctions/?id=" + #ID);
return response;
}
A response looks like this: (https://www.g2a.com/marketplace/product/auctions/?id=27446)
{"a":{"k_709942":{"c":"pl","tr":3451,"f":"\u00a324.71","fb":"\u00a327.18","ci":"565784","cname":"Marketplace User","p":"24.7098173","pb":"27.18431394","ep":"35.15","epb":"38.67","a":"709942","it":"game","t":"1","sl":"0","l":null,"lt":null,"x":0,"v":"all","so":0,"r":99},"k_763218":{"c":"pl","tr":1120,"f":"\u00a324.74","fb":"\u00a327.22","ci":"6533797","cname":"User #f36726dcd","p":"24.7449664","pb":"27.21946304","ep":"35.20","epb":"38.72","a":"763218","it":"game","t":"0","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":92},"k_799750":{"c":"pl","tr":559,"f":"\u00a324.78","fb":"\u00a327.26","ci":"6115711","cname":"Marketplace User","p":"24.7801155","pb":"27.26164196","ep":"35.25","epb":"38.78","a":"799750","it":"game","t":null,"sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":98},"k_722082":{"c":"gb","tr":49066,"f":"\u00a324.96","fb":"\u00a327.45","ci":"1047917","cname":"Marketplace User","p":"24.955861","pb":"27.4514471","ep":"35.50","epb":"39.05","a":"722082","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":98},"k_718113":{"c":"pl","tr":5852,"f":"\u00a324.96","fb":"\u00a327.45","ci":"226876","cname":"Marketplace User","p":"24.955861","pb":"27.4514471","ep":"35.50","epb":"39.05","a":"718113","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":98},"k_739155":{"c":"pl","tr":1208,"f":"\u00a325.43","fb":"\u00a327.98","ci":"6540559","cname":"User #1f948a6a66249","p":"25.43316468854","pb":"27.976481157394","ep":"35.30","epb":"38.83","a":"739155","it":"game","t":"0","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":89},"k_795049":{"c":"pl","tr":50420,"f":"\u00a325.86","fb":"\u00a328.45","ci":"2498689","cname":"Marketplace User","p":"25.86270778","pb":"28.44968154","ep":"36.79","epb":"40.47","a":"795049","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":99},"k_816132":{"c":"pl","tr":22,"f":"\u00a326.00","fb":"\u00a328.60","ci":"6208533","cname":"Marketplace User","p":"25.99627436","pb":"28.59730776","ep":"36.98","epb":"40.68","a":"816132","it":"game","t":"0","sl":"0","l":null,"lt":"0","x":0,"v":"retail","so":0,"r":0},"k_809925":{"c":"pl","tr":81021,"f":"\u00a326.00","fb":"\u00a328.60","ci":"407513","cname":"Marketplace User","p":"26.00330418","pb":"28.60433758","ep":"36.99","epb":"40.69","a":"809925","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"retail","so":0,"r":100},"k_815898":{"c":"cl","tr":1,"f":"\u00a326.01","fb":"\u00a328.61","ci":"7524623","cname":"Marketplace User","p":"26.010334","pb":"28.6113674","ep":"37.00","epb":"40.70","a":"815898","it":"game","t":null,"sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":0},"k_711901":{"c":"pl","tr":12194,"f":"\u00a326.51","fb":"\u00a329.16","ci":"286793","cname":"Marketplace User","p":"26.506689203722","pb":"29.158078610346","ep":"36.79","epb":"40.47","a":"711901","it":"game","t":"1","sl":"0","l":null,"lt":null,"x":0,"v":"all","so":0,"r":99},"k_748710":{"c":"pt","tr":66460,"f":"\u00a326.65","fb":"\u00a329.32","ci":"440288","cname":"Marketplace User","p":"26.650786454082","pb":"29.316585585742","ep":"36.99","epb":"40.69","a":"748710","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"all","so":0,"r":100},"k_709464":{"c":"pl","tr":121341,"f":"\u00a327.02","fb":"\u00a329.72","ci":"1072530","cname":"User #3285e5f8dfcb2","p":"27.0182344425","pb":"29.72005788675","ep":"37.50","epb":"41.25","a":"709464","it":"game","t":"1","sl":"0","l":null,"lt":"0","x":0,"v":"retail","so":0,"r":100},"k_709805":{"c":"pl","tr":11708,"f":"\u00a328.09","fb":"\u00a330.90","ci":"1043113","cname":"User #ca1965d0354a","p":"28.091758957682","pb":"30.901655339702","ep":"38.99","epb":"42.89","a":"709805","it":"game","t":"1","sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":100},"k_725839":{"c":"es","tr":1,"f":"\u00a331.99","fb":"\u00a335.18","ci":"7023396","cname":"Marketplace User","p":"31.985681","pb":"35.1842491","ep":"45.50","epb":"50.05","a":"725839","it":"game","t":null,"sl":"0","l":null,"lt":null,"x":0,"v":"retail","so":0,"r":0},"k_0":{"f":"\u00a332.33","fb":"\u00a335.56","p":"32.33014218","pb":"35.563156398","ep":"45.99","epb":"50.59","a":0,"c":"","rc":"","r":"","tr":0,"t":1,"so":0,"x":0,"n":"G2A.com"}},"w":0}
Any help with will greatly appreciated.
Thanks in advace
So Json is a way for two languages to pass objects to each other. It's just a way to encode an object, so the first part would be to create an object that matches the Json encoding. I was unable to see your example, so I will give you one of my own.
{"Aggregates": [{"ColumnName": "Some Value", "AggregateFunction": "Some Other Value"}], "GroupBy": true}
I would then create a class like this one.
public class JsonAggregates
{
public List<Aggregate> Aggregates { get; set; }
public string GroupBy { get; set; }
}
public class Aggregate
{
public string ColumnName {get; set;}
public string AggregateFunction {get; set;}
}
You can then encode the Json to this new data type with the following code.
using (Stream s = GenerateStreamFromString(json))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(JsonAggregates));
JsonAggregates aggregate = (JsonAggregates)serializer.ReadObject(s);
}

Building json response

I'm working on a self hosting rest api used to monitor de status of several servers.
I was tasked that, when everything is working correctly, I should only return
{"response":"ok"}
But, when there's an error on queried server, or servers, I must return
{ "response" : [ {"agent":"<server>:<port>","port":"<port>" ,"Error":"<Description of the error>"} ] }
I was thinking on building a helper class to build object on this schema and returning them over the rest api
public class HelperErrorResponseClass
{
public string agent { get; set; }
public string port { get; set; }
public string Error { get; set; }
}
This is no problem, the issue is, how to deal when everything it ok. I have this Api response helper class
public class Response
{
public string response { get; set; }
}
But I'm seeing that I'll need to change the response property to List<HelperErrorResponseClass> in order to send the error response. Do you think that, if I stringify the List<HelperErrorResponseClass> object with Json.Net it will be returned in the desired format?
Edit: Forgot to add that, I-m using Web Api to build the rest service.
UDPATE:
After further research, I found a way to work this out.
Following this post, I was able to rewrite the helper classes like this
[DataContract]
[KnownType(typeof(List<HelperErrorResponseClass>))]
public class Response
{
[DataMember]
public object response { get; set; }
}
[DataContract]
public class HelperErrorResponseClass
{
[DataMember(EmitDefaultValue = false)]
public string agent { get; set; }
[DataMember(EmitDefaultValue = false)]
public string port { get; set; }
[DataMember(EmitDefaultValue = false)]
public string error { get; set; }
}
This work to fulfill my and my client needs... except for one little thing. When I get the result from a List, and given that I added the KnownTypes directive, my response is now this
{"response":[{"__type":"HelperErrorResponseClass:#AppCommonLib","Error":"ERROR","InstanceId":"<InstanceId> : <Port>","PortType":"<PortType>"},{"__type":"HelperErrorResponseClass:#AppCommonLib","Error":"ERROR","InstanceId":"<InstanceId> : <Port>","PortType":"<PortType>"}]}
Any idea how to get rid of that __type property of the response? make that it must be explicit to only return the declared properties of the helper class?
Simplest way to deal with this is to set the return type on the handling function to string, then you can check for errors and do something like;
//pseudo code to give an idea
if (errorsList.Count() > 0)
{
return JsonConvert.SerializeObject(errorsList);
}
else
{
return JsonConvert.SerializeObject(new Response("ok"));
}
Now this being said... Unless the people providing requirements aren't at all flexible you should just redo the design. How about just returning the errors array and the person calling the API can infer that if it's length is 0 then everything is working OK. Seems pretty straight forward, right? You could also just put all the properties on one object and those fields would just come back as null or empty strings. Or you could change you serializer settings to exclude them if they don't have a value.
Keep things simple and use an anonymous type.
if (condition)
{
return JsonConvert.SerializeObject(new { response = new { agent = "x", port = "y", error = "z" }});
}
else
{
return JsonConvert.SerializeObject(new { response = "ok"});
}
More info:
https://msdn.microsoft.com/en-us/library/bb397696.aspx
I personally don't think you need a Response class, especially that it is of object type. IMHO, you've overcomplicated the very simple issue that you have. It is not only the __type, but also other info like HelperErrorResponseClass:#AppCommonLib that isn't supposed to be there.
Another Issue you have is the incorrect name of the HelperErrorResponseClass class. This is not a helper class. It is a standard data-object class.
A helper class is a class filled with static methods. It is usually used to isolate a "useful" algorithm.
This is how I would do it:
I'd get rid of the Response class.
I'd use your original simple HelperErrorResponseClass class, but rename it to something more meaningful like ErrorDetails.
I'd return the response like this:
.
if (errorsList.Count() > 0) {
return JsonConvert.SerializeObject(new { response = errorsList});
}
else {
return JsonConvert.SerializeObject(new { response = "ok"});
}
However, if you really want to stick to your updated solution, an easy way to get rid of the __type is simply removing it from the final serialized string:
if (errorsList.Count() > 0) {
string r = JsonConvert.SerializeObject(new { response = errorsList});
return r.Replace("__type", "");
}
else {
return JsonConvert.SerializeObject(new { response = "ok"});
}

How do I deserialize this JSON array (C#)

I am struggling with a subject that has a lot of variants, but I can't seem to find one that works for me, and I think it's because of the way that my JSON array is.
I'm not an expert in C# or JSON, but I already manage to "almost" get this to work. I need to get hand with the class that the JSON will deserialize to.
When I run the code I dont get an error, just a nulls in the xKisokData var.
The JSON data that I am getting. Their are these two different ones.
"{\"Event\": \"sConnection\",\"data[device]\": \"fb16f550-2ef1-11e5-afe9-ff37129acbf4\",\"data[mode]\": \"customer\",\"data[starttime]\": \"2015-07-22T16:07:42.030Z\",\"data[endtime]\": \"\"}"
"{\"Event\": \"Log\",\"data[id]\": \"2015-07-22T16:07:23.063Z\",\"data[messages][0][source]\": \"server\",\"data[messages][0][message]\": \"Server is listening on port 1553\"}"
The code I have so far:
// Read in our Stream into a string...
StreamReader reader = new StreamReader(JSONdataStream);
string JSONdata = reader.ReadToEnd();
JavaScriptSerializer jss = new JavaScriptSerializer();
wsKisokData[] xKisokData = jss.Deserialize<wsKisokData[]>(JSONdata);
My Class:
namespace JSONWebService
{
[DataContract]
[Serializable]
public class KisokEvent
{
public string eventTrigger { get; set; }
}
[DataContract]
[Serializable]
public class KisokData
{
public string data { get; set; }
}
[DataContract]
[Serializable]
public class wsKisokData
{
public KisokEvent KDEvent { get; set; }
public List<KisokData> KDData { get; set; }
}
}
I am sure that I don't understand the Deserialize process. Thanks for the help.
EDIT:
I put the JSON in the top part right from the debugger, here is the strings.
{
"Event": "sConnection",
"data[device]": "fb16f550-2ef1-11e5-afe9-ff37129acbf4",
"data[mode]": "customer",
"data[starttime]": "2015-07-22T16:07:42.030Z",
"data[endtime]": ""
}
{
"Event": "Log",
"data[id]": "2015-07-22T16:07:23.063Z",
"data[messages][0][source]": "server",
"data[messages][0][message]": "Server is listening on port 1553"
}
I would HIGHLY recommend using the json.net package off nuget instead.
You can generate template classes (models) for it by pasting the json into http://json2csharp.com/
Then use said models to convert the json into a c# object (deserializing) by doing a
var jsonStructure = JsonConvert.DeserializeObject<model>(json)
And query as if it was just a standard object
foreach (var x in jsonStructure.KDData)
{
doAction(x.data);
}
// for example

XML Element Selection

I am collecting XML data from a weather website xml file here.
I have created the following code, which finds the first instance of 'temp_c' and returns the value. This is the temperature at the current moment.
using (XmlReader reader = XmlReader.Create(new StringReader(weather)))
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name.Equals("temp_c"))
{
reader.Read();
temp_c = reader.Value;
}
break;
}
}
}
return temp_c
This returns the value of the first instance in the XML file called "temp_c" to the string called "temp_c"
What I would now like to do is use the Element in the XML document called "period" and the element found with period called "fcttext". When "period = 0" it means "today", 1 = tomorrow, etc; and I am after the "fcttext_metric" data that is associated with that period value.
I've been struggling to work the examples and XML reading codes I've found into the current code that I have here. Can anyone please point me in the right direction?
Edit
Here is an example of the XML file:
<forecast>
<forecastday>
<period>0</period>
<fcttext_metric>Sunny</fcttext_metric>
<forecastday>
<period>1</period>
<fcttext_metric>Cloudy</fcttext_metric>
This ended up being more annoying that I originally expected, but you can create an object graph from the XML using a DataContractSerializer and a set of classes that match the XML you are reading.
First, you create your classes, with appropriate DataContract attributes.
[DataContract(Name = "response", Namespace = "")]
public class WeatherData
{
[DataMember(Name = "forecast")]
public Forecast Forecast { get; set; }
}
[DataContract(Name = "forecast", Namespace = "")]
public class Forecast
{
[DataMember(Name = "txt_forecast")]
public TxtForecast TxtForecast { get; set; }
}
[DataContract(Name = "txt_forecast", Namespace = "")]
public class TxtForecast
{
[DataMember(Name = "forecastdays")]
public ForecastDay[] ForecastDays { get; set; }
}
[DataContract(Name = "forecastday", Namespace = "")]
public class ForecastDay
{
[DataMember(Name = "period", Order = 1)]
public int Period { get; set; }
public string FctText { get; set; }
[DataMember(Name = "fcttext", EmitDefaultValue = false, Order = 5)]
private CDataWrapper FctTextWrapper
{
get { return FctText; }
set { FctText = value; }
}
}
Heres where it got complicated. The fcttext element is CDATA, which the DataContractSerializer doesn't support by default.
Using the wonderful answer available at Using CDATA with WCF REST starter kits, you create a CDataWrapper class. I won't repeat the code here (because that would be pointless), just follow the link.
You can see that I've already used the CDataWrapper class above in order to work with the fcttext element.
Once you've got the class structure setup you can use the following code to extract the information you were after. You're just navigating the object graph at this point, so you can use whatever C# you want (I've used a simple LINQ query to find Period 0 and print out the fcttext for it).
var s = new DataContractSerializer(typeof(WeatherData));
var reader = XmlReader.Create("http://api.wunderground.com/api/74e1025b64f874f6/forecast/conditions/q/zmw:00000.1.94787.xml");
var o = (WeatherData)s.ReadObject(reader);
var firstPeriod = o.Forecast.TxtForecast.ForecastDays.Where(a => a.Period == 0).Single();
Console.WriteLine(firstPeriod.FctText);
You can extend the classes as necessary to give you access to additional fields inside the XML. As long as the DataMember names match the XML fields it will all work.
Here's a short summary of some problems I ran into for anyone interested:
I had to set the Namespace attributes of all of the classes to the empty string, because the XML doesn't have any namespace info in it.
The Order attributes were important on the ForecastDay class. If they are omitted, the DataContractSerializer ends up not reading the fcttext field in at all (because it thinks fcttext should come first? not sure why to be honest).

Object reference not set to an instance of an object - LINQ

I am totally stumped on this one. I am getting a "Object reference not set to an instance of an object." error - but I can't figure out why. This is the code that I have:
public class PlayerProfile
{
public List<Profile> PlayerINfo = new List<Profile>();
public void LoadProfiles(string path)
{
XDocument xmlDoc = XDocument.Load(path);
PlayerINfo = new List<Profile>();
// This is where I get the error:
PlayerINfo = (from profiles in xmlDoc.Root.Element("OnlineProfile").Elements("Player")
select new Profile
{
Name = (string)profiles.Element("Name"),
Sex = (string)profiles.Element("Sex"),
Avatar = (string)profiles.Element("Avatar").Attribute("path") ?? "",
Created = (DateTime)profiles.Element("Created")
}).ToList();
}
}
Here is my Profile class:
public class Profile
{
public string Name { get; set; }
public string Sex { get; set; }
public string Avatar { get; set; }
public DateTime Created { get; set; }
}
EDIT - Adding the XML file code:
<?xml version="1.0" encoding="utf-8"?>
<OnlineProfile>
<Player>
<Name>Stacey</Name>
<Sex>Female</Sex>
<Avatar path="/images/Picture.png" />
<Ratio>
<Win>0</Win>
<Loss>0</Loss>
<Abandoned>0</Abandoned>
</Ratio>
<Created>6/19/2011</Created>
</Player>
</OnlineProfile>
from profiles in xmlDoc.Root.Element("OnlineProfile").Elements("Player")
This is the problem - OnlineProfile is your root element, just do
from profiles in xmlDoc.Root.Elements("Player")
Do this: from profiles in xmlDoc.Element("OnlineProfile").Elements("Player") instead of from profiles in xmlDoc.Root.Element("OnlineProfile").Elements("Player")
From the XML you posted "OnlineProfile" is your Root element, so the child elements you expect arent there.
Tried this out + solved this in visual studio. I see the people above beat me to it. Another way to achieve this is:
xmlDoc.Element("OnlineProfile").Elements("Player")
This is what I posted prior to the Xml becomming available...
here's a good candidate for that error
(string)profiles.Element("Avatar").Attribute("...
").Attribute would cause an error. You need to check for null.
e.g.
= profiles.Element("Avatar") != null ? (string)profiles.Element("Avatar").Attribute("... : null;
do you definitely have an element called Avatar in your Xml file. Did the file load in correctly?

Categories