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);
Related
My project has a 3rd party web API that returns a json string in the following format (including the starting and ending curly braces):
{
"866968030210604":{
"dt_server":"2019-02-07 12:21:27",
"dt_tracker":"2019-02-07 12:21:27",
"lat":"28.844968",
"lng":"76.858502",
"altitude":"0",
"angle":"154",
"speed":"9",
"params":{
"pump":"0",
"track":"1",
"bats":"1",
"acc":"0",
"batl":"4"
},
"loc_valid":"1"
},
"866968030221205":{
"dt_server":"2019-02-07 12:20:24",
"dt_tracker":"2019-02-07 12:19:41",
"lat":"28.845904",
"lng":"77.096063",
"altitude":"0",
"angle":"0",
"speed":"0",
"params":{
"pump":"0",
"track":"1",
"bats":"1",
"acc":"0",
"batl":"4"
},
"loc_valid":"1"
},
"866968030212030":{
"dt_server":"0000-00-00 00:00:00",
"dt_tracker":"0000-00-00 00:00:00",
"lat":"0",
"lng":"0",
"altitude":"0",
"angle":"0",
"speed":"0",
"params":null,
"loc_valid":"0"
}
}
I want to deserialize it into a c# class object for further processing. I made the following class structure for the same:
class Params
{
public string pump { get; set; }
public string track { get; set; }
public string bats { get; set; }
public string acc { get; set; }
public string batl { get; set; }
}
class GPSData
{
public string dt_server { get; set; }
public string dt_tracker { get; set; }
public string lat { get; set; }
public string lng { get; set; }
public string altitude { get; set; }
public string angle { get; set; }
public string speed { get; set; }
public Params ObjParams { get; set; }
public string loc_valid { get; set; }
}
and I am trying the following code to deserialize:
JavaScriptSerializer jSerObj = new JavaScriptSerializer();
List<GPSData> lstGPSData = (List<GPSData>)jSerObj.Deserialize(json, typeof(List<GPSData>));
But every time it is showing NULL values assigned to each property of the class after the Deserialize() method is called. Please help me on this.
Your json is not in list format so deserializing to List<> isn't work
So you need to deserialize it into Dictionary<string, GPSData> like
JavaScriptSerializer jSerObj = new JavaScriptSerializer();
Dictionary<string, GPSData> lstGPSData = (Dictionary<string, GPSData>)jSerObj.Deserialize(json, typeof(Dictionary<string, GPSData>));
Usage:
foreach (var item in lstGPSData)
{
string key = item.Key;
GPSData gPSData = item.Value;
}
Also, you can list all your GPSData from above dictionary like,
List<GPSData> gPSDatas = lstGPSData.Values.ToList();
Output: (From Debugger)
I have an HttpClient that makes a call to a REST API.
var response = await client.PostAsync("Payments/CreditCard", content);
var contents = await response.Content.ReadAsStringAsync();
When I read the content of the response as a string, I get the following result:
"\"{\\\"ssl_card_number\\\":\\\"41**********9994\\\",\\\"ssl_exp_date\\\":\\\"1219\\\",\\\"ssl_amount\\\":\\\"50.00\\\",\\\"ssl_salestax\\\":\\\"\\\",\\\"ssl_invoice_number\\\":\\\"\\\",\\\"ssl_departure_date\\\":\\\"\\\",\\\"ssl_completion_date\\\":\\\"\\\",\\\"Test\\\":\\\"\\\",\\\"TestField\\\":\\\"TestValue\\\",\\\"ssl_result\\\":\\\"0\\\",\\\"ssl_result_message\\\":\\\"APPROVAL\\\",\\\"ssl_approval_code\\\":\\\"578380\\\",\\\"ssl_cvv2_response\\\":\\\"U\\\",\\\"ssl_avs_response\\\":\\\"G\\\",\\\"ssl_account_balance\\\":\\\"0.00\\\",\\\"ssl_txn_time\\\":\\\"04/09/2018 09:41:01 AM\\\",\\\"ssl_card_type\\\":\\\"CREDITCARD\\\"}\""
When I debug and inspect the value of the contents variable, it contains the following:
When I try to deserialize the string into a C# object using JSON.Net, I receive an exception, because the contents variable can't be converted to my C# object.
However, if I take the string from the Text Visualizer, I'm able to successfully convert it to my C# object.
Here's the class I'm trying to deserialize the string contents into:
public class PaymentResponse
{
public string ssl_account_balance { get; set; }
public string ssl_amount { get; set; }
public string ssl_approval_code { get; set; }
public string ssl_avs_response { get; set; }
public string ssl_card_number { get; set; }
public string ssl_card_type { get; set; }
public string ssl_completion_date { get; set; }
public string ssl_cvv2_response { get; set; }
public string ssl_departure_date { get; set; }
public string ssl_exp_date { get; set; }
public string ssl_invoice_number { get; set; }
public string ssl_result { get; set; }
public string ssl_result_message { get; set; }
public string ssl_salestax { get; set; }
public string ssl_txn_id { get; set; }
public string ssl_txn_time { get; set; }
}
Here's the code I use for deserializing:
paymentResponse = JsonConvert.DeserializeObject<PaymentResponse>(contents);
How can I get my contents variable to have the same value that appears in the Text Visualizer?
The data shown appears to be serialized twice.
In that case it would need to be deserialized twice.
First to string,
var json = JsonConvert.DeserializeObject<string>(contents);
and then to the desired type
var paymentResponse = JsonConvert.DeserializeObject<PaymentResponse>(json);
#Nkosi was right: first deserialize it to string and then to PaymentResponse:
var contents = "\"{\\\"ssl_card_number\\\":\\\"41**********9994\\\",\\\"ssl_exp_date\\\":\\\"1219\\\",\\\"ssl_amount\\\":\\\"50.00\\\",\\\"ssl_salestax\\\":\\\"\\\",\\\"ssl_invoice_number\\\":\\\"\\\",\\\"ssl_departure_date\\\":\\\"\\\",\\\"ssl_completion_date\\\":\\\"\\\",\\\"Test\\\":\\\"\\\",\\\"TestField\\\":\\\"TestValue\\\",\\\"ssl_result\\\":\\\"0\\\",\\\"ssl_result_message\\\":\\\"APPROVAL\\\",\\\"ssl_approval_code\\\":\\\"578380\\\",\\\"ssl_cvv2_response\\\":\\\"U\\\",\\\"ssl_avs_response\\\":\\\"G\\\",\\\"ssl_account_balance\\\":\\\"0.00\\\",\\\"ssl_txn_time\\\":\\\"04/09/2018 09:41:01 AM\\\",\\\"ssl_card_type\\\":\\\"CREDITCARD\\\"}\"";
var contentAsString = JsonConvert.DeserializeObject<string>(contents);
var paymentResponse = JsonConvert.DeserializeObject<PaymentResponse>(contentAsString);
Console.WriteLine(paymentResponse.ssl_card_number);
Check the fiddle.
Here is the solution. Actually we need to take care about the Encoding while deserializing to object. Since the content string of the object would sometimes have other than ASCII charset. It worked fine for me.
var resultBytes = await response.Content.ReadAsByteArrayAsync();
var actualEncodedString = Encoding.UTF8.GetString(resultBytes);
var actualObject = JsonConvert.DeserializeObject<T>(actualEncodedString);
I would like to read a xml and convert json and then convert that json to an C# object.
Bare in mind that i could use linq to initialize the objects, i know that.
But what i want to a achieve is read the xml convert it to json and from the converted string Deserialize to object. I'm not being able to initialize correctly the object.
What am i missing?
public class Cash
{
public string Amount { get; set; }
}
public class POSLog
{
public string MajorVersion { get; set; }
public string MinorVersion { get; set; }
public string FixVersionive { get; set; }
public Cash Cashx { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
try
{
XmlDocument xml = new XmlDocument();
xml.LoadXml("<POSLog MajorVersion=\"6\" MinorVersion=\"0\" FixVersion=\"0\"><Cash Amount = \"100\"></Cash></POSLog>");
string json = JsonConvert.SerializeObject(xml.InnerXml);
POSLog deserializedProduct = JsonConvert.DeserializeObject<POSLog>(json);
Console.WriteLine("Major Version" + deserializedProduct.MajorVersion);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
You can't serialize a string containing xml into json and expect it to deserialize into a POSLog. Deserialized your xml into a POSLog before you continue.
According to documentation :
Converting between JSON and XML with Json.NET
Conversion Rules
Elements remain unchanged.
Attributes are prefixed with an # and should be at the start of the object.
Single child text nodes are a value directly against an element, otherwise they are accessed via #text.
The XML declaration and processing instructions are prefixed with ?.
Character data, comments, whitespace and significant whitespace nodes are accessed via #cdata-section, #comment, #whitespace and #significant-whitespace respectively.
Multiple nodes with the same name at the same level are grouped together into an array.
Empty elements are null.
If the XML created from JSON doesn't match what you want, then you will need to convert it manually. The best approach to do this is to load your JSON into a LINQ to JSON object like JObject or JArray and then use LINQ to create an XDocument.
With that in mind the following unit test created to solve your problem passes.
[TestClass]
public class JsonToXmlTests : MiscUnitTests {
[TestMethod]
public void Xml_Should_Convert_To_JSON_And_Object() {
string xml = "<POSLog MajorVersion=\"6\" MinorVersion=\"0\" FixVersion=\"0\"><Cash Amount = \"100\"></Cash></POSLog>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc, Newtonsoft.Json.Formatting.None, true);
//Attributes are prefixed with an # and should be at the start of the object.
jsonText = jsonText.Replace("\"#", "\"");
POSLog actual = JsonConvert.DeserializeObject<POSLog>(jsonText);
actual.Should().NotBeNull();
actual.MajorVersion.Should().Be("6");
actual.MinorVersion.Should().Be("0");
actual.FixVersion.Should().Be("0");
actual.Cash.Should().NotBeNull();
actual.Cash.Amount.Should().Be("100");
}
public class Cash {
public string Amount { get; set; }
}
public class POSLog {
public string MajorVersion { get; set; }
public string MinorVersion { get; set; }
public string FixVersion { get; set; }
public Cash Cash { get; set; }
}
}
The problem is you're deserializing the wrong thing.
You have to first deserialize to POSLog from XML and then serialize the POSLog as json.
void Main()
{
try
{
string xmlDoc = "<POSLog MajorVersion=\"6\" MinorVersion=\"0\" FixVersion=\"0\"><Cash Amount = \"100\"></Cash></POSLog>";
XmlSerializer xser = new XmlSerializer(typeof(POSLog));
POSLog fromXml = xser.Deserialize(new StringReader(xmlDoc)) as POSLog;
string json = JsonConvert.SerializeObject(fromXml);
POSLog fromJson = JsonConvert.DeserializeObject<POSLog>(json);
Console.WriteLine("MajorVersion=" + fromJson.MajorVersion);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
// Define other methods and classes here
public class Cash
{
public string Amount { get; set; }
}
public class POSLog
{
[XmlAttribute]
public string MajorVersion { get; set; }
[XmlAttribute]
public string MinorVersion { get; set; }
[XmlAttribute]
public string FixVersionive { get; set; }
public Cash Cashx { get; set; }
}
I have a response from Jira API, require to be deserialized into data model:
com.atlassian.greenhopper.service.sprint.Sprint#40675167[id=10151,rapidViewId=171,state=CLOSED,name=Sprint 37.1,startDate=2015-07-30T16:00:22.000+03:00,endDate=2015-08-13T16:00:00.000+03:00,completeDate=2015-08-13T14:31:34.343+03:00,sequence=10151]
This is actually the information of current sprint for issue.
I need to deserialize it to a model like:
public class Model
{
public string name { get; set; }
...
}
I have already removed all non-required information, like com.atlassian.greenhopper.service.sprint.Sprint#40675167 using Regex pattern \[(.*?)\] so I have brackets and all inside.
Now I stopped completely trying to find the a way to convert this string to a data model.
Found the following thread at the Atlassian Answers page and there appears to be no JSON representation of that inner Object. As shown in the example from that thread:
customfield_10007:[
"com.atlassian.greenhopper.service.sprint.Sprint#a29f07[rapidViewId=<null>,state=CLOSED,name=NORD - Sprint 42,startDate=2013-07-29T06:47:00.000+02:00,endDate=2013-08-11T20:47:00.000+02:00,completeDate=2013-08-14T15:31:33.157+02:00,id=107]",
"com.atlassian.greenhopper.service.sprint.Sprint#769133[rapidViewId=<null>,state=ACTIVE,name=NORD - Sprint 43,startDate=2013-08-14T15:32:47.322+02:00,endDate=2013-08-23T15:32:47.322+02:00,completeDate=<null>,id=117]"
],
The response is indeed a JSON array, but the array itself contains CSV's, so you can make use of the following to parse that:
public class DataObject
{
public string id { get; set; }
public string rapidViewId { get; set; }
public string state { get; set; }
public string name { get; set; }
public string startDate { get; set; }
public string endDate { get; set; }
public string completeDate { get; set; }
public string sequence { get; set; }
}
public class Program
{
private const string sampleStringData =
#"[id=10151,rapidViewId=171,state=CLOSED,name=Sprint 37.1,startDate=2015-07-30T16:00:22.000+03:00,endDate=2015-08-13T16:00:00.000+03:00,completeDate=2015-08-13T14:31:34.343+03:00,sequence=10151]";
static void Main(string[] args)
{
var dataObject = new DataObject();
string[][] splitted;
var sampleWithNoBrackets = sampleStringData.Substring(1,sampleStringData.Length-2);
splitted = sampleWithNoBrackets.Split(',').Select(p => p.Split('=')).ToArray();
dataObject.id = splitted[0][1];
dataObject.rapidViewId = splitted[1][1];
dataObject.state = splitted[2][1];
dataObject.name = splitted[3][1];
dataObject.startDate = splitted[4][1];
dataObject.endDate = splitted[5][1];
dataObject.completeDate = splitted[6][1];
dataObject.sequence = splitted[7][1];
Console.ReadKey();
}
}
Here's the output for the above:
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