I'm trying to deserialize xml retrieved from a web service call
using (var client = new WebClient())
{
client.UseDefaultCredentials = true;
var content = client.DownloadString("call to service");
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<NewCourseApply.Models.Education>));
using (TextReader textReader = new StringReader(content))
{
var e = (List<NewCourseApply.Models.Education>)serializer.Deserialize(textReader);
}
}
The xml returned from the service is:
<ArrayOfEducation xmlns="http://schemas.datacontract.org/2004/07/CovUni.Domain.Admissions" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Education><_auditList xmlns="http://schemas.datacontract.org/2004/07/CovUni.Common.Base" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/><_apCode>670104552</_apCode><_attendanceType>FT</_attendanceType><_educationId>1</_educationId><_establishmentDetails>test school</_establishmentDetails><_fromDate>2016-11-01T00:00:00</_fromDate><_toDate>2016-11-22T00:00:00</_toDate><_ucasSchoolCode/></Education></ArrayOfEducation>
My client side object is:
[Serializable]
public class Education
{
protected int _apCode;
protected int _educationId;
protected string _establishmentDetails;
protected string _ucasSchoolCode;
protected DateTime? _fromDate;
protected DateTime? _toDate;
protected string _attendanceType;
protected string _auditList;
public int ApCode
{ get { return _apCode;}
set { _apCode = value;} }
public int EducationId
{ get { return _educationId;}
set { _educationId = value;} }
public string EstablishmentDetails
{ get { return _establishmentDetails;}
set { _establishmentDetails = value;} }
public string UcasSchoolCode
{ get { return _ucasSchoolCode;}
set { _ucasSchoolCode = value;} }
public DateTime? FromDate
{ get { return _fromDate;}
set { _fromDate = value;} }
public DateTime? ToDate
{ get { return _toDate;}
set { _toDate = value;} }
public string AttendanceType
{ get { return _attendanceType;}
set { _attendanceType = value;} }
public string AuditList
{ get { return _auditList;}
set { _auditList = value;} }
}
The error I am getting is:
There is an error in XML document (1, 2).
<ArrayOfEducation xmlns='http://schemas.datacontract.org/2004/07/CovUni.Domain.Admissions'> was not expected.
Also if I call a web service call and get the singular Education response i.e.:
<Education xmlns="http://schemas.datacontract.org/2004/07/CovUni.Domain.Admissions" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><_auditList xmlns="http://schemas.datacontract.org/2004/07/CovUni.Common.Base" xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/><_apCode>670104552</_apCode><_attendanceType>FT</_attendanceType><_educationId>1</_educationId><_establishmentDetails>test school</_establishmentDetails><_fromDate>2016-11-01T00:00:00</_fromDate><_toDate>2016-11-22T00:00:00</_toDate><_ucasSchoolCode/></Education>
Surely I just need one Simple Education class on the client side that can deserialise from the 2 examples of xml i have provided i.e. array and non array
Can some of you kind souls let me know where i'm going wrong or if there's a better way of doing this?
Many Thanks
Change the Class to
[XmlRoot("ArrayOfEducation", Namespace = "http://schemas.datacontract.org/2004/07/CovUni.Domain.Admissions")]
public class ArrayOfEducation
{
[XmlElement("Education")]
public List<ContainerEducation> education { get; set; }
}
public class ContainerEducation
{
[XmlElement(ElementName = "_apCode")]
public int _apCode { get; set; }
[XmlElement(ElementName = "_educationId")]
public int _educationId { get; set; }
[XmlElement(ElementName = "_establishmentDetails")]
public string _establishmentDetails { get; set; }
[XmlElement(ElementName = "_ucasSchoolCode")]
public string _ucasSchoolCode { get; set; }
[XmlElement(ElementName = "_fromDate")]
public DateTime? _fromDate { get; set; }
[XmlElement(ElementName = "_toDate")]
public DateTime? _toDate { get; set; }
[XmlElement(ElementName = "_attendanceType")]
public string _attendanceType { get; set; }
[XmlElement(ElementName = "_auditList", Namespace = "http://schemas.datacontract.org/2004/07/CovUni.Common.Base")]
public string _auditList { get; set; }
}
And Deserialize below way. Now, when I run the code to deserialize your XML, I do get the objects filled nicely.
XmlSerializer mySerializer = new XmlSerializer(typeof(ArrayOfEducation));
using (TextReader textReader = new StringReader(content))
{
ArrayOfEducation arrEdu = (ArrayOfEducation)mySerializer.Deserialize(textReader);
}
Update as per your comment:
If you are sure that web service is going to send single Education then you need to change the class to
[XmlRoot("ArrayOfEducation", Namespace = "http://schemas.datacontract.org/2004/07/CovUni.Domain.Admissions")]
public class ArrayOfEducation
{
[XmlElement("Education")]
public ContainerEducation education { get; set; }
}
Related
I have a POCO like this:
public class Process
{
public Process() { }
[DataMember(Name = "lang_code")]
public string LCode { get; set; }
[DataMember(Name = "data_currency")]
public string Currency { get; set; }
[DataMember(Name = "country_code")]
public string CCode { get; set; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
Now when I serialize my POCO I get json back like this which has field name:
{"LCode":"en-US","Currency":"USD","CCode":"IN"}
Is there any way to get it the way DataMember fields are after serializing POCO. Something like below:
{"lang_code":"en-US","data_currency":"USD","country_code":"IN"}
Below is the code we have:
ProcessStr = ExtractHeader(headers, PROCESS_HEADER);
Console.WriteLine(ProcessStr);
if (!string.IsNullOrWhiteSpace(ProcessStr))
{
Process = DeserializeJson<Process>(ProcessStr);
if (Process != null && !string.IsNullOrWhiteSpace(Process.Gold))
{
Process.Gold = HttpUtility.HtmlEncode(Process.Gold);
}
ProcessStr = Process.ToString();
Console.WriteLine(ProcessStr);
}
private T DeserializeJson<T>(string str) where T : new()
{
try
{
return Utf8Json.JsonSerializer.Deserialize<T>(str);
}
catch (Exception e)
{
return new T();
}
}
It looks like you are using two different packages, Newtonsoft.Json to serialize and Utf8Json to deserialize. They use different annotations. You can get it to work, but it might be simpler to choose one or the other.
Newtonsoft.Json uses the JsonProperty attribute whereas Utf8Json uses the DataMember one.
using System;
using System.Diagnostics;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Utf8Json;
namespace JSONPropertyTest
{
public class Process
{
public Process() { }
[JsonProperty("lang_code")]
[DataMember(Name = "lang_code")]
public string LCode { get; set; }
[JsonProperty("data_currency")]
[DataMember(Name = "data_currency")]
public string Currency { get; set; }
[JsonProperty("country_code")]
[DataMember(Name = "country_code")]
public string CCode { get; set; }
public override string ToString()
{
return JsonConvert.SerializeObject(this);
}
}
class Program
{
static private T DeserializeJson<T>(string str) where T : new()
{
try
{
return Utf8Json.JsonSerializer.Deserialize<T>(str);
}
catch (Exception e)
{
return new T();
}
}
static void Main(string[] args)
{
var test = new Process { LCode = "en-US",Currency = "USD", CCode = "IN" };
var json = test.ToString();
Console.WriteLine($"serialized={test}");
var deserialized = DeserializeJson<Process>(json);
Debug.Assert(test.CCode == deserialized.CCode);
Debug.Assert(test.LCode == deserialized.LCode);
Debug.Assert(test.Currency == deserialized.Currency);
Console.WriteLine($"deserialized={deserialized}");
}
}
}
To just use Utf8Json you need to update your ToString method, which is the only one in the code you've shown that relies on Newtonsoft.Json. That would look like this:
public class Process
{
public Process() { }
[DataMember(Name = "lang_code")]
public string LCode { get; set; }
[DataMember(Name = "data_currency")]
public string Currency { get; set; }
[DataMember(Name = "country_code")]
public string CCode { get; set; }
public override string ToString()
{
return Utf8Json.JsonSerializer.ToJsonString(this);
}
}
The propblem: There is no "Name" field in the object or csv file, yet CsVHelper keeps looking for "Name" in the header. So why is it tripping there and what are some fixes?
When trying to build objects from a csv file, the following error comes up:
CsvHelper.HeaderValidationException: Header with name 'Name' was not found. If you are expecting some headers to be missing and want to ignore this validation, set the configuration HeaderValidated to null. You can also change the functionality to do something else, like logging the issue.
at CsvHelper.Configuration.ConfigurationFunctions.HeaderValidated(Boolean isValid, String[] headerNames, Int32 headerNameIndex, ReadingContext context)
I have tried setting HeaderValidated to null, but got the same results.
The header of the csv:
Id|Title|Description|AssignedToUserId|SourceUserId|DateCreated|DateAssigned|DateCompleted|Notes
The parsing code:
private static IEnumerable<T> GetCSVData<T>(string fullFileName)
{
PrintMembers<T>();
using (var reader = new StreamReader(fullFileName))
{
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.IncludePrivateMembers = false;
csv.Parser.Configuration.Delimiter = "|";
var records = csv.GetRecords<T>().ToList();
return records;
}
}
}
A quick function for listing the public properties and fields of the class (T) being passed in outputs the following:
Properties...
Id
AssignedToUserId
SourceUserId
Title
Description
AssignedTo
Source
DateCreated
DateAssigned
DateCompleted
RelatedTasks
Notes
Fields...
[None]
They all have getters and setters.
EDIT
The IntermediateTask is the generic being fed into GetCSVData(). It has a default constructor. IntermediateTask is internal, but is in the same assembly as GetCSVData().
Code for the class(es) in question:
internal class IntermediateTask : Task
{
private int _Id;
new public int Id
{
get { return _Id; }
set { _Id = value; }
}
private int _AssignedToUserId;
public int AssignedToUserId
{
get { return _AssignedToUserId; }
set
{
_AssignedToUserId = value;
base.AssignedTo = userManager.Get(_AssignedToUserId);
}
}
private int _SourceUserId;
public int SourceUserId
{
get { return _SourceUserId; }
set
{
this._SourceUserId = value;
base.Source = userManager.Get(_SourceUserId);
}
}
public IntermediateTask() : base("", "", new IntermediateUser(), new IntermediateUser())
{
}
}
public class Task
{
public Task(string title, string description, User assignedTo, User source, DateTime? dateCreated = null, int id = 0)
{
this.RelatedTasks = new List<Task>();
this.Title = title;
this.Description = description;
this.AssignedTo = assignedTo;
this.Source = source;
this.DateCreated = dateCreated ?? DateTime.Now;
this.Id = id;
}
private int _Id;
public int Id
{
get { return _Id; }
protected set { _Id = value; }
}
public string Title { get; set; }
public string Description { get; set; }
public User AssignedTo { get; set; }
public User Source { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateAssigned { get; set; }
public DateTime? DateCompleted { get; set; }
public IList<Task> RelatedTasks { get; set; }
public string Notes { get; set; }
override public string ToString()
{
return $"Id: {Id}; Title: {Title}";
}
}
In my case it complained about AssignedTo missing, but that is actually a property in the class that is not in the csv, so I had to add these two lines to make it work:
csv.Configuration.HeaderValidated = null;
csv.Configuration.MissingFieldFound = null;
I don't know why it would come up with 'Name' unless you have something different.
I have an XML file that I am parsing through and have come across a specific element that has it's own child nodes. The XML file is below:
<status.AppleSettings>
<AppleInstance MaxCost="250" Status="77" NewMode="5" SharePrice="350"
FlagTF="False" TimeClock="0" TimeClockSec="14"
Options="7532890" ID="JK_7755" Owner="SLP90"
Server="PA.SL90.COL" Name="SLP90" GroupName="COL.PA"
Instance="AppleServiceInstance" NewFlag="True" FinalCount="0"/>
<AppleInstance MaxCost="5" Status="0" NewMode="1" SharePrice="0"
FlagTF="False" TimeClock="300" TimeClockSec="1000"
Options="56794577431" Owner="A.CON" Instance="SL91"
NewFlag="True" FinalCount="1" List="1450, 1430"
Keyrepo="SYSTEMSERVER_7671902"/>
</status.AppleSettings>
As you can see, there's a parent node - AppleSettings and then two child nodes w/ the same name - AppleInstance. I created two separate classes for the child nodes since they have different attributes. I am able to access AppleSettings and when I do a quickwatch I can see the two child nodes inside, I just can't figure out how to access them. New to XML parsing and C# so everything is trial and error, learning a lot from stackoverflow.
Here is the code I have to access the AppleSettings parent node:
private List<Data> GetAppleSettingsNode(List<XmlDocument> XMLdocument, List<Data> DataList)
{
for (int i = 0; i < XMLdocument.Count(); i++)
{
AppleSettings temp = new AppleSettings();
var temp2 = XMLdocument[i].DocumentElement.SelectNodes("//AppleSettings");
foreach (var node in temp2)
{
var temp3 = node.ToString();
}
XmlNode xmlNode1 = XMLdocument[i].SelectSingleNode("//AppleSettings");
XmlSerializer serial1 = new XmlSerializer(typeof(AppleSettings));
temp = (AppleSettings)serial1.Deserialize(new XmlNodeReader(xmlNode1));
}
}
Is it even necessry to access the AppleSettings node? Could I go directly to the two AppleInstance child nodes? If someone could help me out, I'd appreciate it. Thanks!
It is better to use LINQ to XML API.
(1) The code below shows how to access any XML attribute by its name.
(2) .FirstOrDefault()?.Value technique will prevent exceptions generation when an attribute is missing.
c#
void Main()
{
const string FILENAME = #"e:\Temp\AppleSettings.xml";
XDocument doc = XDocument.Load(FILENAME);
foreach (var el in doc.Descendants("AppleInstance"))
{
Console.WriteLine("MaxCost={0}", el.Attributes("MaxCost").FirstOrDefault()?.Value);
Console.WriteLine("Instance={0}", el.Attributes("Instance").FirstOrDefault()?.Value);
Console.WriteLine("GroupName={0}", el.Attributes("GroupName").FirstOrDefault()?.Value);
}
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication8
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = (Root)serializer.Deserialize(reader);
}
}
public class Root
{
[XmlArray("status.AppleSettings")]
[XmlArrayItem("AppleInstance")]
public List<ApppleInstance> AppleInstances { get; set; }
}
public class ApppleInstance
{
[XmlAttribute()]
public int MaxCost { get; set; }
[XmlAttribute()]
public int Status { get; set; }
[XmlAttribute()]
public int NewMode { get; set; }
[XmlAttribute()]
public int SharePrice { get; set; }
private Boolean _FlagTF { get; set; }
[XmlAttribute()]
public string FlagTF
{
get { return _FlagTF? "True" : "False";}
set { _FlagTF = (value == "True") ? true : false;}
}
[XmlAttribute()]
public int TimeClock { get; set; }
[XmlAttribute()]
public int TimeClockSec { get; set; }
[XmlAttribute()]
public long Options { get; set; }
[XmlAttribute()]
public string ID { get; set; }
[XmlAttribute()]
public string Owner { get; set; }
[XmlAttribute()]
public string Server { get; set; }
[XmlAttribute()]
public string Name { get; set; }
[XmlAttribute()]
public string GroupName { get; set; }
[XmlAttribute()]
public string Instance { get; set; }
private Boolean _NewFlag { get; set; }
[XmlAttribute()]
public string NewFlag
{
get { return _NewFlag ? "True" : "False"; }
set { _NewFlag = (value == "True") ? true : false; }
}
[XmlAttribute()]
public int FinalCount { get; set; }
private int[] _List { get; set; }
[XmlAttribute()]
public string List
{
get { return string.Join(",",_List);}
set { _List = value.Split(new char[] {','}).Select(x => int.Parse(x)).ToArray() ;}
}
[XmlAttribute()]
public string Keyrepo { get; set; }
}
}
The i of LargeXMLResponse[i] is loop count of the Large XML response if your response tag in wrapped up in between, and if you have a alternative way please go ahead with.
var ResponseToList = LargeXMLResponse[i].Descendants("Response").ToList();
if (ResponseToList.Count() > 0){
for (var pf = 0; pf < ResponseToList.Count(); pf++)
{
ResponseInfoList.Add(new ResponseToList{
id = ResponseToList[pf].Descendants("Block").Attributes("id").Count() > 0 ?
ResponseToList[pf].Descendants("Block ").Attributes("id").First().Value : "",
});
}
}
i have the following class
using System;
public class AppEventsClass
{
public string title { get; set; }
public string description { get; set; }
}
after calling a remote webservice i retrive the following json string:
{"d":"[title\":\"test\",\"description\":\"test desc\"},{\"title\":\"test2\",\"description\":\"desc test 2\"}]"}
after retriving that json string, how can i convert the string in a List<> of AppEventsClass with Newtonsoft?
I tried several solutions, but nothing that works fine for me.
for example this:
List<AppEventsClass> result = new List<AppEventsClass>();
result = JsonConvert.DeserializeObject<List<AppEventsClass>>(content).ToList();
and this is the .asmx that serializes the string:
[ScriptMethod(UseHttpGet = true)]
public string GetEvents()
{
using (mySQLDataContext ctx = new secondosensoSQLDataContext())
{
List<eventi> eventiList = ctx.eventi.ToList();
List<AppEventsClass> eventiClassList = new List<AppEventsClass>();
for (int i = 0; i < eventiList.Count; i++)
{
AppEventsClass a = new AppEventsClass();
a.title = eventiList[i].titlolo_evento;
a.description = eventiList[i].descrizione_evento;
eventiClassList.Add(a);
}
var json = JsonConvert.SerializeObject(eventiClassList);
return json;
}
}
1st issues seems that the response we retrieve is not formed correctly
Assumed that the json string is looking like the following:
{"d":[{"title":"test","description":"test desc"},{"title":"test2","description":"desc test 2"}]}
The correct class for deserialization should look like this
public class Rootobject
{
public D[] d { get; set; }
}
public class D
{
public string title { get; set; }
public string description { get; set; }
}
Thanks
PS. Here is a working example:
class Program
{
static void Main(string[] args)
{
string json = "{\"d\":[{title:\"test\",description:\"test desc\"},{title:\"test2\",description:\"desc test 2\"}]}";
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<Rootobject>(json);
}
}
public class Rootobject
{
public D[] d { get; set; }
}
public class D
{
public string title { get; set; }
public string description { get; set; }
}
I have one xml file and I want to generate custom list from that xml using Linq.
here is my code. But I am not getting any records.Here is my code.
public class TemplateSettings {
public string DecimalSeparator { get; set; }
public string ThousandSeparator { get; set; }
public string DateSeparator { get; set; }
public string TimeSeparator { get; set; }
}
XML Here
<TemplateSetting>
<DecimalSeparator>1</DecimalSeparator>
<ThousandSeparator>2</ThousandSeparator>
<DateSeparator>3</DateSeparator>
<TimeSeparator>4</TimeSeparator>
<DateFormat>dd/MM/yyyy</DateFormat>
<ValueDelimiter>tr</ValueDelimiter>
<QuoteCharacter>r</QuoteCharacter>
<IsHeader>False</IsHeader>
</TemplateSetting>
And my code to get object from xml is
var a = (from x in objTemplateMasterEAL.TemplatSettingsXML.Elements("TemplateSetting")
select new TemplateSettings()
{
DateFormat = (string)x.Element("DateFormat"),
DecimalSeparator = (string)x.Element("DecimalSeparator"),
ThousandSeparator = (string)x.Element("ThousandSeparator"),
DateSeparator = (string)x.Element("DateSeparator"),
TimeSeparator = (string)x.Element("TimeSeparator"),
QuoteCharacter = (string)x.Element("QuoteCharacter"),
ValueDelimiter = (string)x.Element("ValueDelimiter"),
IsHeaderLine = (bool)x.Element("IsHeader")
}).ToList<TemplateSettings>();
Can any one suggest me what is wrong here ?
If your goal is just to deserialize the XML to object you can simply use this:
class Program
{
static void Main(string[] args)
{
using (StreamReader reader = new StreamReader("Sample.xml"))
{
var serializer = new XmlSerializer(typeof(TemplateSetting));
var templateSetting = (TemplateSetting)serializer.Deserialize(reader);
}
}
}
[XmlRoot]
public class TemplateSetting
{
public string DecimalSeparator { get; set; }
public string ThousandSeparator { get; set; }
public string DateSeparator { get; set; }
public string TimeSeparator { get; set; }
}
I make only on one change and its working fine for me.
<TemplateSettings>
<TemplateSetting>
<DecimalSeparator>1</DecimalSeparator>
<ThousandSeparator>2</ThousandSeparator>
<DateSeparator>3</DateSeparator>
<TimeSeparator>4</TimeSeparator>
<DateFormat>dd/MM/yyyy</DateFormat>
<ValueDelimiter>tr</ValueDelimiter>
<QuoteCharacter>r</QuoteCharacter>
<IsHeader>False</IsHeader>
</TemplateSetting>
</TemplateSettings>