XML Parsing via XmlReader: Read XMLElement Name as String - c#

I have run into a problem while trying to parse the response of a WebDAV application.
The relevant part of the response looks like this:
for collections:
....
<D:getlastmodified xmlns:B="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" B:dt="dateTime.rfc1123">Tue, 15 Jan 2013 15:47:30 GMT</D:getlastmodified>
<D:displayname>aaa.bc</D:displayname>
<D:resourcetype>
<D:collection />
</D:resourcetype>
<D:getcontenttype>text/html; charset=utf-8</D:getcontenttype>
....
for normal files:
....
<D:getlastmodified xmlns:B="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/" B:dt="dateTime.rfc1123">Tue, 15 Jan 2013 15:47:30 GMT</D:getlastmodified>
<D:displayname>aaa.bc</D:displayname>
<D:resourcetype />
<D:getcontenttype>text/html; charset=utf-8</D:getcontenttype>
....
I want to parse this into a c# object with the property:
[XmlElement("resourcetype")]
public string Type {get;set;}
Where e.g. Type = "collection" for a collection.
How would I do this? For the part I posted my C# code looks like this (but does not do what I want):
[XmlRoot("prop")]
public class Prop
{
[XmlElement("creationdate")]
public string CreationDate { get; set; }
[XmlElement("getlastmodified")]
public string LastModified { get; set; }
[XmlElement("displayname")]
public string DisplayName { get; set; }
[XmlElement("resourcetype")]
public string ResourceType { get; set; }
[XmlElement("getcontenttype")]
public string ContentType { get; set; }
[XmlElement("getcontentlength")]
public string ContentLength { get; set; }
[XmlElement("getetag")]
public string ETag { get; set; }
[XmlElement("imagewidth")]
public string ImageWidth { get; set; }
[XmlElement("imageheight")]
public string ImageHeight { get; set; }
[XmlElement("thumbnailuri")]
public string TumbnailUri { get; set; }
}
[XmlRoot("resourcetype")]
public class ResourceType
{
[XmlElement("collection")] // TODO
public string Collection { get; set; }
}
and the method to parse everything:
private T ParseWebDavXml<T>(string xml)
{
using (var reader = XmlReader.Create(new StringReader(xml)))
{
var serializer = new XmlSerializer(typeof(T), "DAV:");
var result = (T)serializer.Deserialize(reader);
return result;
}
}

Check this Link: I have tested this code
Remove the FirtsColumn, SecondColumn from the code and utilize the xmlDS as per your requirements
XML Parsing

You can change the string type to an object type for the ResourceType fied. You also need to decorate ResourceType fied with XmlType attributes. You specify on XmlType attribute by target (in your case, 2).
You also need to create two types :
One for the string,
One for the collection.
But you can use two more simpler solutions :
generate a XSD and the C# classes corresponding to this XSD : see [https://stackoverflow.com/questions/19359691/diff-between-top-1-1-and-select-1-in-sql-select-query/19359757#19359757],
directly define a table, instead of a string field

Related

Convert JSON string to object C#

I have JSON string results as follows.
In this response Sometimes sizeKey and sizeName properties are returned as a string. But sometimes both properties are returns inside an array as follows
I am using following code to convert it to object
var assets = jObject["assets"].Children().ToList();
foreach (var item in assets)
{
decorationAssets.Add(item.ToObject<AEDecorationAssets>());
}
And my AEDecorationAssets class is as follows.
public class AEDecorationAssets
{
public string Id { get; set; }
public string Url { get; set; }
public string[] Colors { get; set; }
public string FontKey { get; set; }
public string SizeKey { get; set; }
public string ViewKey { get; set; }
public string FontName { get; set; }
public int Rotation { get; set; }
public string SizeName { get; set; }
public string TextValue { get; set; }
public string EntityType { get; set; }
public string LocationCode { get; set; }
public string LocationName { get; set; }
public string TextEffectKey { get; set; }
public string TextEffectName { get; set; }
public string DecorationMethod { get; set; }
public string NumDecorationColors { get; set; }
}
At the time when "sizeKey" is an array, the above code gives an error. How can I resolve this issue? Is there any JSON property we can use to resolve it?
One way you can do it is by making your SizeKey type an object (i.e. public object SizeKey { get; set; }), then you can switch/case on item.ToObject<AEDecorationAssets>().SizeKey.GetType() to figure out how to handle it (i.e. if String do this, if JArray do that), etc.
If a JSON type is sometime an array, and sometimes a string, you can't really map it simply to a .NET type, as there is none that supports this behavior.
So first you need a datatype that can store this, like and string[] or List<string>.
It could be that JsonConvert will solve this automatically, but otherwise you'll need to write a custom ContractResolver or JsonConverter. Here you can detect if the source property is a string or array. If it's an array, you can use the default deserialization. If it is a string, you need to convert it to an array with a single value.
Simply get json result for which you want to create c# object and then you can valid json response from https://jsonlint.com/ and then you can create c# object of any type json response which you want through http://json2csharp.com. And after get c# object of your json response you only need to deserialization of your json response to c# object which you have created. which will return you expected result.

parsing Json with weird attribute names [duplicate]

How can we parse if json fields contains a colon(:)? Like this:
{
"dc:creator":"Jordan, Micheal",
"element:publicationName":"Applied Ergonomics",
"element:issn":"2839749823"
}
In fact I wonder how to do this with a library like restsharp, for mapping?
Using Json.Net
string json = #"{
""dc:creator"":""Jordan, Micheal"",
""element:publicationName"":""Applied Ergonomics"",
""element:issn"":""2839749823""
}";
var pub = JsonConvert.DeserializeObject<Publication>(json);
public class Publication
{
[JsonProperty("dc:creator")]
public string creator { set; get; }
[JsonProperty("element:publicationName")]
public string publicationName { set; get; }
[JsonProperty("element:issn")]
public string issn { set; get; }
}
OR
Console.WriteLine(JObject.Parse(json)["dc:creator"]);
If you use DataContractJsonSerializer, DataMemberAttribute has property Name which can be used to override default name. This means that when you deserialize json value of property dc:creator is assigned to Publication::Creator property and on the contrary when you serialize C# object.
For example:
public class Publication
{
[DataMember(Name="dc:creator")]
public string Creator { set; get; }
[DataMember(Name="element:publicationName")]
public string PublicationName { set; get; }
[DataMember(Name="element:issn")]
public string Issn { set; get; }
}
If you choose to use Json.Net, #L.B's answer is the way to go.

Deserialize Json String not working

I want to deserialize a Json string from a php website. Unfortunately every time I try it, it will return null for medianPrice....Why?
public class PriceInfo
{
public string success { get; set; }
public double lowestPrice { get; set; }
public string volume { get; set; }
public string medianPrice { get; set; }
}
WebClient client = new WebClient();
string url = "http://steamcommunity.com/market/priceoverview/?country=US&currency=1&appid=730&market_hash_name=" + name;
byte[] html = client.DownloadData(url);
UTF8Encoding utf = new UTF8Encoding();
string return_value = utf.GetString(html);
PriceInfo priceInfo = new JavaScriptSerializer().Deserialize<PriceInfo>(return_value);
if( Double.Parse(priceInfo.medianPrice) > 0.15 )
{
string blablu = "hello";
}
The Json which returns from the website is the following:
{"success":true,"lowest_price":"$0.04","volume":"3,952","median_price":"$0.02"}
I hope you can help me!
I am strongly recommending that you try using Newtonsoft.Json
you will find that it is easier to handle your Jason objects
your code will be like this (Untested)
PriceInfo defaultCallResult = JsonConvert.DeserializeObject<PriceInfo>(return_value);
Your JSON property is named "median_price" (with an underscore), but your C# property is "medianPrice".
You could use Json.NET which will allow you to change the mapping using attributes.
Using Json.NET, decorate your medianPrice property as follows:
[JsonProperty(PropertyName = "median_price")]
public string medianPrice { get; set; }
I'm not sure how JavaScriptSerializer succeeds in parsing your class at all, as the keys hardly match match the class properties.
JavaScriperSerializer is obsolete, I'd recommend you use another serializer, such as Json.NET:
public class PriceInfo
{
[JsonProperty("success")]
public string Success { get; set; }
[JsonProperty("lowest_price")]
public double LowestPrice { get; set; }
[JsonProperty("volume")]
public string Volume { get; set; }
[JsonProperty("median_price")]
public string MedianPrice { get; set; }
}
And when you want to deserialize:
PriceInfo priceInfo = JsonConvert.DeserializeObject<PriceInfo>(returnValue);
First of all, as mentioned in the other answers, your property names do not match.
So take
public class PriceInfo
{
public string success { get; set; }
public string lowest_price { get; set; }
public string volume { get; set; }
public string median_price { get; set; }
}
edit: as mentioned by Yuval, you cannot use JsonProperty with JavaScriptSerializer so you need to stick with the property names from the json.
Then, there is currency information in the json. So you need to get rid of these:
string return_value = "{\"success\":true,\"lowest_price\":\"$0.04\",\"volume\":\"3,952\",\"median_price\":\"$0.02\"}";
string return_valueconverted = HttpUtility.HtmlDecode(return_value);
PriceInfo priceInfo = new JavaScriptSerializer().Deserialize<PriceInfo>(return_valueconverted);
priceInfo.lowest_price = priceInfo.lowest_price.TrimStart('$');
priceInfo.median_price = priceInfo.median_price.TrimStart('$');
As you can see, this does HtmlDecode these values and afterwards trims the dollar sign from the value.
See more about Html character set here:
http://www.w3.org/MarkUp/html-spec/html-spec_13.html

How to deserialize XML string fragment?

I have an object that has some properties that are XML string fragments. I want to take those and further deserialize them into objects for easier use. How can I do that using the .NET XML Serializer?
Here's an example of the XML string fragment:
<Addr1></Addr1>
<Addr2></Addr2>
<Addr3></Addr3>
<Addr4></Addr4>
<City></City>
<State></State>
<PostalCode></PostalCode>
<Country></Country>
So far my attempts have resulted in this exception:
<Addr1 xmlns=''> was not expected.
If you want to deserialize the fragments into objects I assume you have a strongly typed object so you could just create a helper method to add a root element using the type name of the object you are trying to deserialize
Example:
public T DeserializeFragment<T>(string xmlFragment)
{
// Add a root element using the type name e.g. <MyData>...</MyData>
var xmlData = string.Format("<{0}>{1}</{0}>", typeof(T).Name, xmlFragment);
var mySerializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(xmlData))
{
return (T)mySerializer.Deserialize(reader);
}
}
Usage:
public class MyData
{
public string Addr1 { get; set; }
public string Addr2 { get; set; }
public string Addr3 { get; set; }
public string Addr4 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
string fragment = #"<Addr1>2</Addr1>
<Addr2>2</Addr2>
<Addr3>2</Addr3>
<Addr4>2</Addr4>
<City>2</City>
<State>2</State>
<PostalCode>2</PostalCode>
<Country>2</Country>";
var result = DeserializeFragment<MyData>(fragment);

deserialising does not work

This is the xml stream:
<?xml version="1.0" encoding="utf-8" ?>
<historydetails>
<taskEvent>
<eventtype>Transitions</eventtype>
<historyevent>Task moved</historyevent>
<details>From 'Requested' to 'In Validation'</details>
<author>NAme</author>
<entrydate>01 Jul 13, 11:34</entrydate>
<historyid>2620</historyid>
</taskEvent>
<taskEvent>
<eventtype>Updates</eventtype>
<historyevent>Subtask marked done</historyevent>
<details>Subtask: visualise status and versions</details>
<author>NAme2</author>
<entrydate>21 Jun 13, 10:16</entrydate>
<historyid>2588</historyid>
</taskEvent>
</historydetails>
The corresponding classes look like this:
public class historydetails
{
[XmlElement("taskEvent")]
List<taskEvent> eventList = new List<taskEvent>();
}
public class taskEvent
{
string eventtype { get; set; }
string historyevent { get; set; }
string details { get; set; }
string author { get; set; }
string entrydate { get; set; }
string historyid { get; set; }
}
the code to deserialise the xml (the string replacement contains the xml code):
XmlSerializer deserializer = new XmlSerializer(typeof(historydetails));
object obj = obj = deserializer.Deserialize(stringToStream(replacement));
historydetails XmlData = (historydetails)obj;
The method stringToStream
private MemoryStream stringToStream(string input)
{
byte[] byteArray = Encoding.ASCII.GetBytes(input);
MemoryStream stream = new MemoryStream(byteArray);
return stream;
}
The result that i get is as following:
The object XmlData is made and there is a list of taskEvents.
The problem is in the list itself: it is empty...
You have to make the members public
public class historydetails
{
[XmlElement("taskEvent")]
public List<taskEvent> eventList = new List<taskEvent>();
}
public class taskEvent
{
public string eventtype { get; set; }
public string historyevent { get; set; }
public string details { get; set; }
public string author { get; set; }
public string entrydate { get; set; }
public string historyid { get; set; }
}
As an aside, for future reference (with Visual Studio 2012 or the WebEssentials plugin), one of the easiest way to create the classes based on some sample XML content data is to copy it into the clipboard and then use the built-in VS function: EDIT - > Paste Special -> Paste XML As Classes into a new class file.
It leaves less space for errors like the one you encountered and
It's fast, you'll have your classes ready in a few seconds

Categories