Deserialize list of objects with list - c#

I have the following XML:
<?xml version="1.0" encoding="utf-8"?>
<CallEvents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CallEvent>
<Time>2014-02-24T06:44:27.12</Time>
<Type>Inner</Type>
<Fs>
<StrPair>
<Key>Name</Key>
<Value>Call1</Value>
</StrPair>
<StrPair>
<Key>Owner</Key>
<Value>Ali</Value>
</StrPair>
</Fs>
</CallEvent>
<CallEvent>
<Time>2014-02-24T06:44:29.089</Time>
<Type>Outer</Type>
<Fs>
<StrPair>
<Key>Name</Key>
<Value>Call2</Value>
</StrPair>
<StrPair>
<Key>Id</Key>
<Value>3242</Value>
</StrPair>
<StrPair>
<Key>Another</Key>
<Value>123</Value>
</StrPair>
</Fs>
</CallEvent>
</CallEvents>
I tried to deserialize it, but it doesn't want to deserialize list Fs. I get CallEvents with CallEvent items, and members of CallEvent filled with correct values except list Fs. The list Fs is empty. Why?
What do I do wrong?
class Program
{
static void Main(string[] args)
{
string xmlFile = "call_events.xml";
CallEvents events = CallEvents.OpenFromXmlFile(xmlFile);
Console.ReadKey();
}
}
[Serializable]
public class CallEvent
{
[XmlElement]
public DateTime Time;
[XmlElement]
public CallEventType Type;
public CallEvent()
{
this.Fields = new Dictionary<string, string>();
}
[XmlArray("Fs"), XmlArrayItem("StrPair")]
public List<StrPair> Fs
{
get
{
var list = new List<StrPair>();
foreach (var pair in Fields)
{
list.Add(new StrPair(pair.Key, pair.Value));
}
return list;
}
set
{
Fields.Clear();
foreach (var dictPair in value)
{
Fields.Add(dictPair.Key, dictPair.Value);
}
}
}
[XmlIgnore]
public Dictionary<string, string> Fields;
public void ParseFields(List<LogMessage> eventLogMessages)
{
int eventLogMessagesCount = eventLogMessages.Count;
this.Fields.Clear();
for (int i = 0; i < eventLogMessagesCount; i++)
{
LogMessage logMessage = eventLogMessages[i];
int pos = logMessage.Message.IndexOf(": ");
if(pos == -1)
continue;
string fieldName = logMessage.Message.Substring(0, pos);
pos+=2;
string fieldValue = logMessage.Message.Substring(pos);
if (this.Fields.ContainsKey(fieldName))
{
this.Fields[fieldName] += ("\r\n" + fieldValue);
}
else
{
this.Fields.Add(fieldName, fieldValue);
}
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0} {1} | ", Type, Time);
foreach (var pair in Fields)
{
sb.AppendFormat("{0}: {1}, ", pair.Key, pair.Value);
}
return sb.ToString();
}
[Serializable]
public class StrPair
{
[XmlElement]
public string Key;
[XmlElement]
public string Value;
public StrPair() { }
public StrPair(string key, string value)
{
Key = key;
Value = value;
}
}
}
[XmlRoot("CallEvents")]
public class CallEvents : List<CallEvent>
{
static public CallEvents OpenFromXmlFile(string xmlFileName)
{
CallEvents callEvents;// = new CallEvents();
XmlSerializer ser = new XmlSerializer(typeof(CallEvents));
XmlReader xmlReader = new XmlTextReader(xmlFileName);
try
{
callEvents = (CallEvents)ser.Deserialize(xmlReader);
}
finally
{
xmlReader.Close();
}
return callEvents;
}
public void SaveToXmlFile(string xmlFileName)
{
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = System.Text.Encoding.UTF8;
xmlWriterSettings.Indent = true;
XmlSerializer ser = new XmlSerializer(this.GetType());
XmlWriter xmlWriter = null;
tryAgain:
try
{
xmlWriter = XmlTextWriter.Create(xmlFileName, xmlWriterSettings);
ser.Serialize(xmlWriter, this);
}
catch (Exception ex)
{
System.Windows.Forms.DialogResult dr = System.Windows.Forms.MessageBox.Show("Couldn't serialize to XML. Details: " + ex.Message, "Error", System.Windows.Forms.MessageBoxButtons.RetryCancel, System.Windows.Forms.MessageBoxIcon.Warning);
if (dr == System.Windows.Forms.DialogResult.Retry)
{
goto tryAgain;
}
}
finally
{
if (xmlWriter != null)
{
xmlWriter.Close();
}
}
}
}

I havn'e used this in a while so the code might need some touching up.
CallEvents events;
using(XmlReader reader = XmlReader.Create("call_events.xml"))
{
XmlDeserializer deSerializer = new XmlDeserializer(typeof(CallEvents));
events = (CallEvents)deSerializer.Deserialize(reader);
}

Related

Object resulting from xml deserialization only has 1 element, despite xml having multiple elements

I'm trying to test the serialization for webrequests.
I'm doing a unit test where I:
- create a mock response from the server
- deserialize that response
- Compare initial object with deserialized one
The issue is one of my arrays in only partially populated where instead of all the elements, it only has one, the last one.
Deserialization has to be made by hand because of xml schema limitations.
Item is a partial class to separate the DTO from the xml operations
I have tried to change the attributes of the array property to
[XmlArray("items")]
[XmlArrayItemAttribute("item")]
I have tested just the serialization-deserialization of an individual item and it works.
I have checked both the xml resulting from the original serialization and the xml which is deseriliazed and they are equal.
First the item itself:
[XmlRoot("item")]
public partial class InvoiceItem
{
[XmlElement(ElementName = "name")]
public string Name { get; set; }
}
Now the array:
[XmlArray("items")]
[XmlArrayItemAttribute("item")]
public InvoiceItem[] InvoiceItems
{
get
{
return this.invoiceItems;
}
set
{
this.invoiceItems = value;
}
}
Finally the deserializator:
public void ReadXml(XmlReader reader)
{
Regex regexTaxName = new Regex(#"tax\d_name");
Regex regexTaxType = new Regex(#"tax\d_type");
Regex regexTaxPercent = new Regex(#"tax\d_percent");
Regex regexTaxNumber = new Regex(#"\d");
List<Tax> taxesList = new List<Tax>();
while (reader.Read())
{
Debug.WriteLine(reader.GetAttribute("name"));
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name.Equals("name", StringComparison.Ordinal))
{
reader.Read();
this.Name = reader.Value;
}
else if (reader.Name.Equals("type", StringComparison.Ordinal))
{
ProductType value = ProductType.Product;
reader.Read();
if (Enums.TryParse<ProductType>(reader.Value, out value))
{
this.Type = value;
}
}
else if (reader.Name.Equals("description", StringComparison.Ordinal))
{
reader.Read();
this.Description = reader.Value;
}
else if (reader.Name.Equals("unit_cost", StringComparison.Ordinal))
{
float value = 0;
reader.Read();
if (float.TryParse(reader.Value, out value))
{
this.UnitCost = value;
}
}
else if (reader.Name.Equals("quantity", StringComparison.Ordinal))
{
int value = 0;
reader.Read();
if (int.TryParse(reader.Value, out value))
{
this.Quantity = value;
}
}
else if (reader.Name.Equals("discount", StringComparison.Ordinal))
{
float value = 0;
reader.Read();
if (float.TryParse(reader.Value, out value))
{
this.Discount = value;
}
}
else if (reader.Name.Equals("discount_type", StringComparison.Ordinal))
{
NumericalSignificance value = NumericalSignificance.Percent;
reader.Read();
if (Enums.TryParse<NumericalSignificance>(reader.Value, out value))
{
this.DiscountType = value;
}
}
else if (regexTaxName.IsMatch(reader.Name))
{
int taxNumber = int.Parse(regexTaxNumber.Match(reader.Name).Value, CultureInfo.CurrentCulture);
if (taxesList.Count < taxNumber)
{
reader.Read();
Tax newTax = new Tax();
newTax.Name = reader.Value;
taxesList.Add(newTax);
}
else
{
reader.Read();
taxesList[taxNumber-1].Name = reader.Value;
}
}
else if (regexTaxPercent.IsMatch(reader.Name))
{
int taxNumber = int.Parse(regexTaxNumber.Match(reader.Name).Value, CultureInfo.CurrentCulture);
if (taxesList.Count > taxNumber)
{
Tax newTax = new Tax();
float value = 0;
reader.Read();
if (float.TryParse(reader.Value, out value))
{
newTax.TaxPercent = value;
}
taxesList.Add(newTax);
}
else
{
float value = 0;
reader.Read();
if (float.TryParse(reader.Value, out value))
{
taxesList[taxNumber-1].TaxPercent = value;
}
}
}
else if (regexTaxType.IsMatch(reader.Name))
{
int taxNumber = int.Parse(regexTaxNumber.Match(reader.Name).Value, CultureInfo.CurrentCulture);
if (taxesList.Count > taxNumber)
{
Tax newTax = new Tax();
NumericalSignificance value = NumericalSignificance.Percent;
reader.Read();
if (Enums.TryParse<NumericalSignificance>(reader.Value, out value))
{
newTax.Type = value;
}
taxesList.Add(newTax);
}
else
{
NumericalSignificance value = NumericalSignificance.Percent;
reader.Read();
if (Enums.TryParse<NumericalSignificance>(reader.Value, out value))
{
taxesList[taxNumber-1].Type = value;
}
}
}
}
}
taxesArr = taxesList.ToArray();
}
The problems is on the items array where the end object only has the final object instead of all the original ones.
EDIT:
An example that shows the issue:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
[XmlRoot("invoice")]
public class Invoice
{
[XmlArray("items")]
private InvoiceExampleItem[] items;
[XmlArray("items")]
public InvoiceExampleItem[] Items
{
get { return this.items; }
set { this.items = value; }
}
}
[XmlRoot("item", Namespace = "")]
public partial class InvoiceExampleItem : IXmlSerializable
{
[XmlElement(ElementName = "name")]
public string Name { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name.Equals("name", StringComparison.Ordinal))
{
reader.Read();
this.Name = reader.Value;
}
}
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("name", this.Name);
}
}
[TestClass]
public class ExampleTest : AutoMoqTest
{
[TestMethod]
public void ExampleDeserialization()
{
InvoiceExampleItem item1 = new InvoiceExampleItem()
{
Name = "item1"
};
InvoiceExampleItem item2 = new InvoiceExampleItem()
{
Name = "item2"
};
InvoiceExampleItem item3 = new InvoiceExampleItem()
{
Name = "item3"
};
Invoice mockInvoice = new Invoice()
{
Items = new InvoiceExampleItem[] { item1, item2, item3 }
};
XmlDocument mockInvoiceSerialized = SerializeInvoice(mockInvoice);
XmlDocument mockResponseXml = GenerateXmlResponse(mockInvoiceSerialized);
GetInvoiceResponse response = DeserializeXML<GetInvoiceResponse>(mockResponseXml.OuterXml);
Invoice resultInvoice = response.Invoice;
if (mockInvoice.Items.Length != resultInvoice.Items.Length)
{
throw new Exception("wrong number of items");
}
}
public XmlDocument SerializeInvoice(Invoice invoiceToSerialize)
{
XmlDocument toReturn = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(typeof(Invoice));
XmlReaderSettings settings = new XmlReaderSettings();
XmlDocument itemsDocument = GetTemplateXML();
InvoiceExampleItem[] items = invoiceToSerialize.Items;
MemoryStream memStm = null, tempStream = null;
try
{
memStm = tempStream = new MemoryStream();
using (StreamWriter sw = new StreamWriter(memStm, Encoding.UTF8))
{
// Serialize object into raw xml
memStm = null;
serializer.Serialize(sw, invoiceToSerialize);
sw.Flush();
// parse raw xml into Xml document
tempStream.Position = 0;
settings.IgnoreWhitespace = true;
var xtr = XmlReader.Create(tempStream, settings);
toReturn.Load(xtr);
}
}
finally
{
if (memStm != null)
{
memStm.Dispose();
}
}
return toReturn;
}
public static T DeserializeXML<T>(string responseString)
where T : class
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StringReader sr = new StringReader(responseString))
{
return (T)xmlSerializer.Deserialize(sr);
}
}
public XmlDocument GetTemplateXML()
{
XmlDocument toReturn = new XmlDocument();
var decl = toReturn.CreateXmlDeclaration("1.0", "utf-8", string.Empty);
toReturn.AppendChild(decl);
return toReturn;
}
private XmlDocument GenerateXmlResponse(XmlDocument innerXMLDocument)
{
XmlDocument toReturn = GetTemplateXML();
XmlElement requestElement = toReturn.CreateElement("response");
requestElement.SetAttribute("status", "success");
requestElement.InnerXml = innerXMLDocument.DocumentElement.OuterXml;
toReturn.AppendChild(requestElement);
return toReturn;
}
/// <summary>
/// Web response from creating a invoice
/// </summary>
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", ElementName = "response")]
public class GetInvoiceResponse
{
/// <summary>
/// Gets or sets the response status
/// </summary>
/// <value>
/// reponse Status
/// </value>
[XmlAttribute("status")]
public string ResponseStatus { get; set; }
/// <summary>
/// Gets or sets the new invoice id
/// </summary>
/// <value>
/// generated by invoicera for this response
/// </value>
[XmlElement(ElementName = "invoice")]
public Invoice Invoice { get; set; }
}
}
The solution was to create a class for the array and implement the IXMLSeriazable interface in that class and removing the interface from the item class.
Then, when the xml in the items class, I cycle the tags and create an item individually, adding it to the array next.
For some reason, the method was not exiting when it processed each <\item> tag, so I added a condition to exit the cycle.
Here is the complete code:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
[XmlRoot("invoice")]
public class Invoice
{
public Items items { get; set; }
}
[XmlRoot("item", Namespace = "")]
public partial class InvoiceExampleItem
{
[XmlElement(ElementName = "name")]
public string Name { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name.Equals("name", StringComparison.Ordinal))
{
reader.Read();
this.Name = reader.Value;
return;
}
}
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("name", this.Name);
}
}
public class Items : IXmlSerializable
{
[XmlElement("item")]
public List<InvoiceExampleItem> list = new List<InvoiceExampleItem>();
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
while (reader.ReadToFollowing("item"))
{
InvoiceExampleItem currentItem = new InvoiceExampleItem();
currentItem.Name = reader.Value;
list.Add(currentItem);
}
}
public void WriteXml(XmlWriter writer)
{
foreach(InvoiceExampleItem item in list)
{
writer.WriteStartElement("item");
item.WriteXml(writer);
writer.WriteEndElement();
}
}
}
[TestClass]
public class ExampleTest : AutoMoqTest
{
[TestMethod]
public void ExampleDeserialization()
{
/**/
InvoiceExampleItem item1 = new InvoiceExampleItem()
{
Name = "item1"
};
InvoiceExampleItem item2 = new InvoiceExampleItem()
{
Name = "item2"
};
InvoiceExampleItem item3 = new InvoiceExampleItem()
{
Name = "item3"
};
Items items = new Items();
InvoiceExampleItem item21 = new InvoiceExampleItem()
{
Name = "item1"
};
InvoiceExampleItem item22 = new InvoiceExampleItem()
{
Name = "item2"
};
InvoiceExampleItem item23 = new InvoiceExampleItem()
{
Name = "item3"
};
items.list.Add(item21);
items.list.Add(item22);
items.list.Add(item23);
Invoice mockInvoice = new Invoice()
{
items = items
};
/**/
XmlDocument mockInvoiceSerialized = SerializeInvoice(mockInvoice);
XmlDocument mockResponseXml = GenerateXmlResponse(mockInvoiceSerialized);
GetInvoiceResponse test = new GetInvoiceResponse();
GetInvoiceResponse response = DeserializeXML<GetInvoiceResponse>(mockResponseXml.OuterXml);
Invoice resultInvoice = response.Invoice;
mockResponseXml.Save("C:\\Users\\360Imprimir\\Desktop\\mockResponseXml");
mockInvoiceSerialized.Save("C:\\Users\\360Imprimir\\Desktop\\mockInvoiceSerialized.Xml");
if (mockInvoice.items.list.Count != resultInvoice.items.list.Count)
{
throw new Exception("wrong number of items");
}
}
public XmlDocument SerializeInvoice(Invoice invoiceToSerialize)
{
XmlDocument toReturn = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(typeof(Invoice));
XmlReaderSettings settings = new XmlReaderSettings();
XmlDocument itemsDocument = GetTemplateXML();
MemoryStream memStm = null, tempStream = null;
try
{
memStm = tempStream = new MemoryStream();
using (StreamWriter sw = new StreamWriter(memStm, Encoding.UTF8))
{
// Serialize object into raw xml
memStm = null;
serializer.Serialize(sw, invoiceToSerialize);
sw.Flush();
// parse raw xml into Xml document
tempStream.Position = 0;
settings.IgnoreWhitespace = true;
var xtr = XmlReader.Create(tempStream, settings);
toReturn.Load(xtr);
}
}
finally
{
if (memStm != null)
{
memStm.Dispose();
}
}
return toReturn;
}
public static T DeserializeXML<T>(string responseString)
where T : class
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StringReader sr = new StringReader(responseString))
{
return (T)xmlSerializer.Deserialize(sr);
}
}
public XmlDocument GetTemplateXML()
{
XmlDocument toReturn = new XmlDocument();
var decl = toReturn.CreateXmlDeclaration("1.0", "utf-8", string.Empty);
toReturn.AppendChild(decl);
return toReturn;
}
private XmlDocument GenerateXmlResponse(XmlDocument innerXMLDocument)
{
XmlDocument toReturn = GetTemplateXML();
XmlElement requestElement = toReturn.CreateElement("response");
requestElement.SetAttribute("status", "success");
requestElement.InnerXml = innerXMLDocument.DocumentElement.OuterXml;
toReturn.AppendChild(requestElement);
return toReturn;
}
/// <summary>
/// Web response from creating a invoice
/// </summary>
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", ElementName = "response")]
public class GetInvoiceResponse
{
/// <summary>
/// Gets or sets the response status
/// </summary>
/// <value>
/// reponse Status
/// </value>
[XmlAttribute("status")]
public string ResponseStatus { get; set; }
/// <summary>
/// Gets or sets the new invoice id
/// </summary>
/// <value>
/// generated by invoicera for this response
/// </value>
[XmlElement(ElementName = "invoice")]
public Invoice Invoice { get; set; }
}
}

Serialize and De-serialize XML with commented sections in C#

I was wondering that how i can keep the commented part in XML (After serialization).
Is there any way to do so?
Here is my problem,
I have XML file with lots of nodes. My .NET application will load the XML file and serialize into C# class. Then will change some nodes (by BL) in the class and de-serialize and save the file again.
After saving, the comments i kept on some nodes are disappeared.
Is there is any way to avoid resetting of XML comments using C# ?
Thanks in advance
Suppose an xml like this
<?xml version="1.0" encoding="utf-8"?>
<Test>
<!--Foo Description!-->
<Foo>FooText</Foo>
<!--Bar Description!-->
<Bar>BarText</Bar>
</Test>
var xml = GenericSerializator<Test>.LoadObjectFromFile("test.xml");
xml.Foo += "1";
xml.FooCommnet += "2";
xml.Bar += "3";
xml.BarCommnet += "4";
GenericSerializator<Test>.SaveObjectToFile(xml, "test2.xml");
<?xml version="1.0" encoding="utf-16"?>
<Test>
<!--Foo Description!2-->
<Foo>FooText1</Foo>
<!--Bar Description!4-->
<Bar>BarText3</Bar>
</Test>
we can do it using this code:
internal static class GenericSerializator<T> where T : class
{
public static T LoadObjectFromFile(string fileName)
{
using (var file = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
var xmlSerializer = new XmlSerializer(typeof(T));
return (T)xmlSerializer.Deserialize(file);
}
}
public static void SaveObjectToFile(object value, string fileName)
{
var xmlSerializer = new XmlSerializer(typeof(T));
using (var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
fileStream.Seek(0, SeekOrigin.End);
using (var streamWriter = new StreamWriter(fileStream, Encoding.Unicode))
{
xmlSerializer.Serialize(streamWriter, value);
}
}
}
}
public class Test : XmlSerializableWithComments
{
[XmlIgnore, Description]
public string FooCommnet { get; set; }
public string Foo { get; set; }
[XmlIgnore, Description]
public string BarCommnet { get; set; }
public string Bar { get; set; }
}
public class XmlSerializableWithComments : IXmlSerializable
{
private PropertyInfo[] Properties { get; set; }
public XmlSerializableWithComments()
{
Properties = GetType().GetProperties();
}
public void WriteXml(XmlWriter writer)
{
foreach (var propertyInfo in Properties)
{
var value = propertyInfo.GetValue(this, null).ToString();
if (propertyInfo.IsDefined(typeof(DescriptionAttribute), false))
{
writer.WriteComment(value);
}
else
{
writer.WriteElementString(propertyInfo.Name, value);
}
}
}
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(XmlReader reader)
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.EndElement)
{
reader.Read();
}
string comment = null;
if (reader.NodeType == XmlNodeType.Comment)
{
comment = reader.Value;
}
reader.Read();
if (reader.NodeType == XmlNodeType.Element)
{
var propertyName = reader.LocalName;
PropertyInfo temp;
if ((temp = Properties.FirstOrDefault(i => i.Name == propertyName)) != null)
{
reader.Read();
temp.SetValue(this, reader.Value);
if (!string.IsNullOrEmpty(comment))
{
if ((temp = Properties.FirstOrDefault(i => i.Name == propertyName + "Commnet")) != null)
{
temp.SetValue(this, comment);
}
comment = null;
}
}
}
}
}
}
}

How to Desalinize XML API Response with Multiple Attributes with same name

I Want to read this an XML Respones of a web api
I Want to Deserialize it but i am getting an error
i have already read many documentary on this topic but i cant resolve this on
<ArrayOfServiceAreas xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://tempuri.org/">
<ServiceAreas>
<City>
<string>ABDUL HAKIM /TULAMBA</string>
<string>ABOTTABAD</string>
<string>AHMED PUR EAST</string>
<string>ALI PUR</string>
<string>ALI PUR CHATTA</string>
<string>ARIF WALA</string>
<string>ATTOCK</string>
<string>BADIN</string>
<string>BAGH (AJK)</string>
<string>BANU</string>
<string>BAT KHELA</string>
<string>BAWALNAGAR</string>
<string>BHAI PHERU</string>
<string>BHAKKAR</string>
<string>BHALWAL</string>
<string>BHAWALPUR</string>
<string>BUREWALA</string>
<string>CHAKWAL</string>
<string>CHAMAN</string>
<string>CHARSADA</string>
<string>CHICHAWATNI</string>
<string>CHINNIOT</string>
<string>CHISTIAN</string>
<string>CHITRAL</string>
<string>D.G. KHAN</string>
<string>D.I. KHAN</string>
<string>DADU</string>
<string>DADYAL (AJK)</string>
<string>DALBANDIN</string>
<string>DARA ADAM KHEL</string>
<string>DARGAI</string>
</City>
</ServiceAreas>
</ArrayOfServiceAreas>
In C# i have created two classes given below to deserialize object
[Serializable]
public class City
{
[System.Xml.Serialization.XmlElement("string")]
public string[] String { get; set; }
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("ArrayOfServiceAreas")]
public class ArrayOfServiceAreas
{
[XmlArray("ServiceAreas")]
[XmlArrayItem("City", typeof(City))]
public City[] City { get; set; }
}
This is the controller where i am calling the above classes
with XML Serializer
public ActionResult City()
{
string Perameters = $"username={"myusername"}&password={"mypassword"}&AccountNo={"somenumber"}";
string u = "http://mraabta.mulphico.pk/mnpconsignments/pushtomnp.asmx/Get_Cities?"+Perameters;
var client = new RestClient(u);
var request = new RestRequest(Method.GET);
request.RequestFormat = DataFormat.Xml;
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
var responce = client.Execute(request);
//var r = JsonConvert.DeserializeObject<dynamic>(responce.Content);
System.IO.StringReader SR = new System.IO.StringReader(responce.Content.ToString());
XmlSerializer serializer = new XmlSerializer(typeof(MNP_Plus.Dserializer.MNPCities.ArrayOfServiceAreas));
MNP_Plus.Dserializer.MNPCities.ArrayOfServiceAreas List = (MNP_Plus.Dserializer.MNPCities.ArrayOfServiceAreas)serializer.Deserialize(SR);
return View();
}
Response Content Is Given Above in XML Form which i want to read.
it gives an error
There is an error in XML document (2, 2).
How can i resolve this.
Didn't found any solution for my Question in time so I did it the old fashioned way
If someone else get into this mess then the solution could be
private List<string> GetCities(string Responce)
{
List<string> list = new List<string>();
bool Collection = false;
string item = "";
int count = 0;
foreach (char i in Responce)
{
if (Collection)
{
if(i == '<') { list.Add(item); item = ""; Collection = false; }
else { item = item + i; }
}
if (count == 0) { if (i == '<') { count = 1; } }
else if (count == 1) { if (i == 's') { count = 2; } else { count = 0; } }
else if (count == 2) { if (i == 't') { count = 3; } else { count = 0; } }
else if (count == 3) { if (i == 'r') { count = 4; } else { count = 0; } }
else if (count == 4) { if (i == 'i') { count = 5; } else { count = 0; } }
else if (count == 5) { if (i == 'n') { count = 6; } else { count = 0; } }
else if (count == 6) { if (i == 'g') { count = 7; } else { count = 0; } }
else if (count == 7) { if (i == '>') { Collection = true; } count = 0; }
}
return list;
}
Make changes according to your problem.
The issue is in your mapping classes.
To make your life easier , you can use an online xml2csharp online tool to get the proper POCOs. Here
They should look like this :
[XmlRoot(ElementName = "City", Namespace = "http://tempuri.org/")]
public class City
{
[XmlElement(ElementName = "string", Namespace = "http://tempuri.org/")]
public List<string> String { get; set; }
}
[XmlRoot(ElementName = "ServiceAreas", Namespace = "http://tempuri.org/")]
public class ServiceAreas
{
[XmlElement(ElementName = "City", Namespace = "http://tempuri.org/")]
public City City { get; set; }
}
[XmlRoot(ElementName = "ArrayOfServiceAreas", Namespace = "http://tempuri.org/")]
public class ArrayOfServiceAreas
{
[XmlElement(ElementName = "ServiceAreas", Namespace = "http://tempuri.org/")]
public ServiceAreas ServiceAreas { get; set; }
[XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsd { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
}
I was able to read your XML file without any issues.
Here is the serializer I used :
public class Serializer
{
public T Deserialize<T>(string input) where T : class
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (StringReader stringReader = new StringReader(input))
{
return (T)xmlSerializer.Deserialize(stringReader);
}
}
public string Serialize<T>(T ObjectToSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(ObjectToSerialize.GetType());
StringBuilder builder = new StringBuilder();
using (StringWriterWithEncoding textWriter = new StringWriterWithEncoding(builder, Encoding.UTF8))
{
xmlSerializer.Serialize(textWriter, ObjectToSerialize);
return textWriter.ToString();
}
}
}
public class StringWriterWithEncoding : StringWriter
{
Encoding encoding;
public StringWriterWithEncoding(StringBuilder builder, Encoding encoding)
: base(builder)
{
this.encoding = encoding;
}
public override Encoding Encoding
{
get { return encoding; }
}
}
And Finally here is the execution:
var serializer = new Serializer();
//I used a local file for testing, but it should be the same thing with your api response
var xmlInputData = File.ReadAllText(#"MyXmlPath");
var output = serializer.Deserialize<ArrayOfServiceAreas>(xmlInputData);

looping through json array in c#

I have a json string like,
{"objectType" : "Subscriber", "objectList":[{"firstName":"name1","email":"email#example.com","address":"exampleAddress"},{"firstName":"name2","email":"email2#example.com","address":"exampleAddress2"}]}
I need to parse it in my C# code. I have tried,
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
object routes_list = json_serializer.DeserializeObject(myjson here);
But i cant loop through the "objectList" array. How it can be done?
var jsonObj = new JavaScriptSerializer().Deserialize<RootObj>(json);
foreach (var obj in jsonObj.objectList)
{
Console.WriteLine(obj.address);
}
public class ObjectList
{
public string firstName { get; set; }
public string email { get; set; }
public string address { get; set; }
}
public class RootObj
{
public string objectType { get; set; }
public List<ObjectList> objectList { get; set; }
}
Hint: You can use this site to convert your json string to c# classes
EDIT
using Json.Net
dynamic jsonObj = JsonConvert.DeserializeObject(json);
foreach (var obj in jsonObj.objectList)
{
Console.WriteLine(obj.address);
}
var routes_list = (Dictionary<string, object>)json_serializer.DeserializeObject(myjson);
foreach (var record in routes_list)
{
Console.WriteLine(record);
}
This worked for me, converts to JSON to YAML essentially
string JSONDeserialized {get; set;}
public int indentLevel;
private bool JSONDictionarytoYAML(Dictionary<string, object> dict)
{
bool bSuccess = false;
indentLevel++;
foreach (string strKey in dict.Keys)
{
string strOutput = "".PadLeft(indentLevel * 3) + strKey + ":";
JSONDeserialized+="\r\n" + strOutput;
object o = dict[strKey];
if (o is Dictionary<string, object>)
{
JSONDictionarytoYAML((Dictionary<string, object>)o);
}
else if (o is ArrayList)
{
foreach (object oChild in ((ArrayList)o))
{
if (oChild is string)
{
strOutput = ((string)oChild);
JSONDeserialized += strOutput + ",";
}
else if (oChild is Dictionary<string, object>)
{
JSONDictionarytoYAML((Dictionary<string, object>)oChild);
JSONDeserialized += "\r\n";
}
}
}
else
{
strOutput = o.ToString();
JSONDeserialized += strOutput;
}
}
indentLevel--;
return bSuccess;
}
usage
Dictionary<string, object> JSONDic = new Dictionary<string, object>();
JavaScriptSerializer js = new JavaScriptSerializer();
try {
JSONDic = js.Deserialize<Dictionary<string, object>>(inString);
JSONDeserialized = "";
indentLevel = 0;
DisplayDictionary(JSONDic);
return JSONDeserialized;
}
catch (Exception)
{
return "Could not parse input JSON string";
}

serialize and store object in another object that implements IXmlSerializable

I would like to XML serialize instances of my object Exception and store it in the XMLNode[] Nodes property of another object ExceptionReport.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Xml.Serialization.XmlSchemaProviderAttribute("ExportSchema")]
[System.Xml.Serialization.XmlRootAttribute(IsNullable = false)]
public partial class ExceptionReport : object, System.Xml.Serialization.IXmlSerializable
{
public System.Xml.XmlNode[] Nodes { get; set; }
public void ReadXml(System.Xml.XmlReader reader)
{
this.Nodes = System.Runtime.Serialization.XmlSerializableServices.ReadNodes(reader);
}
public void WriteXml(System.Xml.XmlWriter writer)
{
System.Runtime.Serialization.XmlSerializableServices.WriteNodes(writer, this.Nodes);
}
}
public class Exception
{
public string ExceptionText;
public string exceptionCode;
public string locator;
}
How would i go about doing this so the result would be something like this:
<ExceptionReport xmlns="http://www.opengis.net/ows" >
<Exception exceptionCode="1">my first instance</Exception>
<Exception exceptionCode="2">my second instance</Exception>
</ExceptionReport>
So far i have the following but i need to know how to serialize these objects and store them in the ExceptionReport Nodes array.
ExceptionReport er = new ExceptionReport();
Exception exception_item1 = new Exception();
exception_item1.ExceptionText = "my first instance";
exception_item1.exceptionCode = "1";
Exception exception_item2 = new Exception();
exception_item2.ExceptionText = "my second instance";
exception_item2.exceptionCode = "2";
List<Exception> exceptions = new List<Exception>( exception_item1, exception_item2 );
[XmlRoot("ExceptionReport")]
public partial class ExceptionReport
{
[XmlElement("Exception")]
public List<Exception> Nodes { get; set; }
public ExceptionReport()
{
Nodes = new List<Exception>();
}
}
public class Exception
{
[XmlText]
public string ExceptionText;
[XmlAttribute("exceptionCode")]
public int ExceptionCode;
[XmlAttribute("locator")]
public string Locator;
}
Then to serialize, I use the following extensions:
public static bool XmlSerialize<T>(this T item, string fileName)
{
return item.XmlSerialize(fileName, true);
}
public static bool XmlSerialize<T>(this T item, string fileName, bool removeNamespaces)
{
object locker = new object();
XmlSerializerNamespaces xmlns = new XmlSerializerNamespaces();
xmlns.Add(string.Empty, string.Empty);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
lock (locker)
{
using (XmlWriter writer = XmlWriter.Create(fileName, settings))
{
if (removeNamespaces)
{
xmlSerializer.Serialize(writer, item, xmlns);
}
else { xmlSerializer.Serialize(writer, item); }
writer.Close();
}
}
return true;
}
public static T XmlDeserialize<T>(this string s)
{
object locker = new object();
StringReader stringReader = new StringReader(s);
XmlTextReader reader = new XmlTextReader(stringReader);
try
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
lock (locker)
{
T item = (T)xmlSerializer.Deserialize(reader);
reader.Close();
return item;
}
}
finally
{
if (reader != null)
{ reader.Close(); }
}
}
public static T XmlDeserialize<T>(this FileInfo fileInfo)
{
string xml = string.Empty;
using (FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read))
{
using (StreamReader sr = new StreamReader(fs))
{
return sr.ReadToEnd().XmlDeserialize<T>();
}
}
}
Use like this:
ExceptionReport report = new ExceptionReport();
report.Nodes.Add(new Exception { ExceptionText = "my first instance", ExceptionCode = 1, Locator = "loc1" });
report.Nodes.Add(new Exception { ExceptionText = "my second instance", ExceptionCode = 2 });
report.XmlSerialize("C:\\test.xml");
I tested and it came out like you wanted. Hope it helps...
PS - The extensions came from my library on codeproject: http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx

Categories