How to Desalinize XML API Response with Multiple Attributes with same name - c#

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);

Related

First serialization success, second fails? Why?

I have a method that serialize communication data. First the parameters is serialized into the main CallInformation object as string, then the CallInformation object will also be serialized and then later written to file :
_jSONSettings = new System.Runtime.Serialization.Json.DataContractJsonSerializerSettings();
_jSONSettings.DateTimeFormat = new DateTimeFormat("yyyy-MM-ddThh:mm:ss.fffZ");
_xmlWriterSettings = new System.Xml.XmlWriterSettings() { Indent = true };
var callInformation = logEvent.Properties.Values.First() as CallInformation;
DataContractJsonSerializer serializer;
if (TakeCharsInParameterObject > 0)
{
var counter = 0;
foreach (object param in callInformation.Parameters)
{
using (var stream = new MemoryStream())
{
serializer = new DataContractJsonSerializer(param.GetType(), _jSONSettings);
using (var xmlWriter = System.Xml.XmlWriter.Create(stream, _xmlWriterSettings))
{
serializer.WriteObject(xmlWriter, param);
stream.Flush();
stream.Position = SkipCharsInParameterObject;
using (var streamReader = new StreamReader(stream))
{
var buffer = new char[TakeCharsInParameterObject];
if (streamReader.Peek() >= 0)
{
streamReader.Read(buffer, 0, buffer.Length);
counter++;
callInformation.SerializedParameters += "{Parameter" + counter + ": " + new string(buffer) + "}";
}
}
}
}
}
}
var restult = "";
using (var stream = new MemoryStream())
{
serializer = new DataContractJsonSerializer(typeof(CallInformation), _jSONSettings);
using (var xmlWriter = System.Xml.XmlWriter.Create(stream, _xmlWriterSettings))
{
serializer.WriteObject(xmlWriter, callInformation);
stream.Flush();
stream.Position = 0;
using (var streamReader = new StreamReader(stream))
{
if (streamReader.Peek() >= 0)
restult = streamReader.ReadToEnd();
}
}
}
return restult;
The serialization for parameters works great but the second part do not. After stream.WriteObject the lengh of the stream and the position is still 0?
The CallInformation is a simple DataContract class that looks like this :
[DataContract]
public class CallInformation
{
public CallInformation()
{ }
[DataMember]
public string Address { get; set; }
[DataMember]
public Boolean IsEmpty { get; set; }
[DataMember]
public Boolean IsFaulted { get; set; } = false;
[DataMember]
public string Action { get; set; }
[DataMember]
public CallOrder CallDirection { get; set; }
public DateTime EventTime { get; set; } = DateTime.Now;
[DataMember]
public TimeSpan Duration { get; set; }
[DataMember]
public Boolean IsCallback { get; set; } = false;
[DataMember]
public string LogSource { get; set; } = "Unknown";
[DataMember]
public string SerializedParameters { get; set; } = "";
public List<object> Parameters { get; set; } = new List<object>();
[DataMember]
public string EventTimeDisplay
{
get { return EventTime.ToString("HH:mm:ss.fffffff"); }
set { }
}
}
Why is not the second serialization working?
XmlWriter has got internal buffer, you need to flush it to have stream position changed:
serializer.WriteObject(xmlWriter, callInformation);
xmlWriter.Flush();
stream.Position = 0;

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; }
}
}

Skip reading the first line of the csv file

I am a beginner in programming,It's really difficult for me to analyze and debug how to skip reading the first line of the csv file. I need some help.
I need my id to fill my combobox in my form that contains all
Id's.In order to not include the header in browsing and
displaying.I need to skip the first line.
public bool ReadEntrie(int id, ref string name, ref string lastname, ref
string phone, ref string mail, ref string website)
{
int count = 0;
CreateConfigFile();
try
{
fs = new FileStream(data_path, FileMode.Open);
sr = new StreamReader(fs);
string temp = "";
bool cond = true;
while (cond == true)
{
if ((temp = sr.ReadLine()) == null)
{
sr.Close();
fs.Close();
cond = false;
if (count == 0)
return false;
}
if (count == id)
{
string[] stringSplit = temp.Split(',');
int _maxIndex = stringSplit.Length;
name = stringSplit[0].Trim('"');
lastname = stringSplit[1].Trim('"');
phone = stringSplit[2].Trim('"');
mail = stringSplit[3].Trim('"');
website = stringSplit[4].Trim('"');
}
count++;
}
sr.Close();
fs.Close();
return true;
}
catch
{
return false;
}
}
#Somadina's answer is correct, but I would suggest a better alternative. You could use a CSV file parser library such as CSV Helpers.
You can get the library from Nuget or Git. Nuget command would be:
Install-Package CsvHelper
Declare the following namespaces:
using CsvHelper;
using CsvHelper.Configuration;
Here's how simple your code looks when you use such a library:
class Program
{
static void Main(string[] args)
{
var csv = new CsvReader(File.OpenText("Path_to_your_csv_file"));
csv.Configuration.IgnoreHeaderWhiteSpace = true;
csv.Configuration.RegisterClassMap<MyCustomObjectMap>();
var myCustomObjects = csv.GetRecords<MyCustomObject>();
foreach (var item in myCustomObjects.ToList())
{
// Apply your application logic here.
Console.WriteLine(item.Name);
}
}
}
public class MyCustomObject
{
// Note: You may want to use a type converter to convert the ID to an integer.
public string ID { get; set; }
public string Name { get; set; }
public string Lastname { get; set; }
public string Phone { get; set; }
public string Mail { get; set; }
public string Website { get; set; }
public override string ToString()
{
return Name.ToString();
}
}
public sealed class MyCustomObjectMap : CsvClassMap<MyCustomObject>
{
public MyCustomObjectMap()
{
// In the name method, you provide the header text - i.e. the header value set in the first line of the CSV file.
Map(m => m.ID).Name("id");
Map(m => m.Name).Name("name");
Map(m => m.Lastname).Name("lastname");
Map(m => m.Phone).Name("phone");
Map(m => m.Mail).Name("mail");
Map(m => m.Website).Name("website");
}
}
Some more details in an answer here.
To skip the first line, just replace the line:
if (count == id)
with
if (count > 0 && count == id)
MORE THOUGHTS ON YOUR APPROACH
Because you used the ref keyword, each line you read will override the previous values you stored in the parameters. A better way to do this is to create a class to hold all the properties of interest. Then, for each line you read, package an instance of the class and add it to a list. You method signature (even the return type) will change eventually.
From your code, the class will look like this:
public class DataModel
{
public string Name { get; set; }
public string LastName { get; set; }
public string Phone{ get; set; }
public string Mail { get; set; }
public string Website{ get; set; }
}
Then your method will be like this:
public IList<DataModel> ReadEntrie(int id, string data_path)
{
int count = 0;
CreateConfigFile();
var fs = new FileStream(data_path, FileMode.Open);
var sr = new StreamReader(fs);
try
{
var list = new List<DataModel>();
string temp = "";
bool cond = true;
while (cond == true)
{
if ((temp = sr.ReadLine()) == null)
{
cond = false;
if (count == 0)
throw new Exception("Failed");
}
if (count > 0 && count == id)
{
string[] stringSplit = temp.Split(',');
var item = new DataModel();
item.Name = stringSplit[0].Trim('"');
item.LastName = stringSplit[1].Trim('"');
item.Phone = stringSplit[2].Trim('"');
item.Mail = stringSplit[3].Trim('"');
item.Website = stringSplit[4].Trim('"');
// add item to list
list.Add(item);
}
count++;
}
return list;
}
catch
{
throw; // or do whatever you wish
}
finally
{
sr.Close();
fs.Close();
}
}

get int value from XmlTextAttribute when deserialize xml to class in c#

xml as below :
<Item>
<Winner>2</Winner>
</Item>
For my class definition I have the following:
public enum HomeOrAwayTeamType {Home =1,Away =2,Draw =3,NA = 0};
class Item
{
[XmlIgnore]
public virtual HomeOrAwayTeamType Winner { get; set; }
[XmlElement(ElementName = "Winner"), XmlText]
public virtual string WinnerSerializer
{
get { return this.Winner.ToString(); }
set
{
//get 'Away' from HomeOrAwayTeamType
this.Winner = (HomeOrAwayTeamType)2; //ok
this.Winner = (HomeOrAwayTeamType)Convert.ToInt32("2"); //ok
this.Winner = (HomeOrAwayTeamType)int.parse("2"); //ok
//get 'NA' from HomeOrAwayTeamType
this.Winner = (HomeOrAwayTeamType)Convert.ToInt32(value); //fail
this.Winner = (HomeOrAwayTeamType)int.parse(value); //fail
}
}
}
string xml = ""; //xml code
Item model = default(Item);
using (var reader = XmlReader.Create(new StringReader(xml)))
{
var serializer = new XmlSerializer(typeof(Item));
model = (Item)serializer.Deserialize(reader);
}
hi, guys..
How get int value from XmlTextAttribute?
Please help~
Your xml string is empty. This works for me:
string xml = "<Item><Winner>2</Winner></Item>"; //xml code
this.Winner gets set to Away

LINQ2XML approach to generalize iteration through xml

I am trying to parse some xml files (using LINQ) to use that data to store in DB. Following is the format for one of the service, and there are dozens of them more, each with different node patterns and structure.
Is there a way to generalize this approach, so that I can iterate all these services through a single method/lines of code? without being bothered by how the childNodes are arranged ?
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<deviceState>
<id>203948-2908093-203984902-29348020-290lk</id>
<device>Mirron</device>
<variable>
<id>Plug - Meter.VI</id>
<text>
<textValue>
<value>0.000000</value>
</textValue>
</text>
</variable>
<variable>
<id>AEB</id>
<text>
<textStr>-</textStr>
</text>
</variable>
<variable>
<id>DESCRIPTION</id>
<text>
<textStr />
</text>
</variable>
<variable>
<id>VDTTM</id>
<text>
<textDate>
<date>01042016103658</date>
</textDate>
</text>
</variable>
<variable>
<id>STATUS</id>
<text>
<textValue>
<value>1.000000</value>
</textValue>
</text>
</variable>
</deviceState>
I want to achieve a functionality, where I can access values of every variable id by specifying a search filter and then access it's value directly, without being bothered by following meaningless tags.
<text><textValue> or <text><textDate> or <text><textStr/> or <text>
<textvalue><value>
something like, lets say new devices {a.id=node("id"), a.value=node("valu")}.
Currently I am using following code which does the trick but its not efficient, neither in speed, nor in manageability.
XDocument x = XDocument.Parse(_back);
string back = "";
string xvalue, yvalue;
foreach (XElement xe in x.Descendants().Take(1))
{
var s = xe.Value.IndexOf("Plug - Meter.VI");
var val = xe.Value.Substring(s, 25);
back= val.Substring(val.LastIndexOf("I")+1, 10);
break;
}
Any guidance will be highly appreciated. Thanks
Based on Monty's feedback, this is what I am using.
public protoDCM_CornerL08UMS_View()
{
InitializeComponent();
synchronizationContext = SynchronizationContext.Current;
StartingMeter();
}
private async void StartingMeter()
{
string val="0";
max = min = 0;
await Task.Run(() =>
{
do
{
UpdateUI(val,max,min);
val = fetchData();
Double temp =0;
if (Double.TryParse(val,out temp))
{
if(min==0&&max==0)
{
min = max = temp;
}
if(temp>max)
{
max = temp;
}
if(temp<min)
{
min = temp;
}
}
val = temp.ToString();
}
while (true);
});
}
private void UpdateUI(string value, Double _max , Double _min)
{
var timeNow = DateTime.Now;
if ((DateTime.Now - previousTime).Milliseconds <= 50) return;
synchronizationContext.Post(new SendOrPostCallback(o =>
{
lblInstant.Text= (string)o;
}), value);
synchronizationContext.Post(new SendOrPostCallback(o =>
{
lblMax.Text = (string)o;
}), _max.ToString());
synchronizationContext.Post(new SendOrPostCallback(o =>
{
lblMin.Text = (string)o;
}), _min.ToString());
previousTime = timeNow;
}
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
private string fetchData()
{
String _back = HttpGet("http://xxx.xxx.xxx"+Global.Node.Current.Device.Address+"/services/devices/deviceState.xml?id=D83AE139-E0C9-4B15-B2A9-6E0B57B28ED1?type=ALL");
//_back = FormatXML(Response);
try
{
DeviceState deserializedXML = new DeviceState();
XmlSerializer serializer = new XmlSerializer(typeof(DeviceState));
using (Stream stream = GenerateStreamFromString(_back))
{
deserializedXML = (DeviceState)serializer.Deserialize(stream);
var x = (from z in deserializedXML.Variable
where z.Id == "Plug - Meter.VI"
select new
{
Id = z.Id,
value= (z.Text.TextDate == null?
(z.Text.TextStr == null
? (z.Text.TextValue == null
? "No Text Value!" : z.Text.TextValue.Value.ToString()) : z.Text.TextStr.ToString()) : z.Text.TextDate.Date.ToString()) }).FirstOrDefault();
return x.value;
}
}
catch (Exception w)
{
MessageBox.Show(w.ToString());
return "0.0";
}
}
public static string HttpGet(string URI)
{
try
{
System.Net.WebRequest req = System.Net.WebRequest.Create(URI);
req.Method = "GET";
System.Net.WebResponse resp = req.GetResponse();
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream());
return sr.ReadToEnd().Trim();
}
catch (Exception sl)
{
return sl.ToString();
}
}
Try this....
Usings
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
Classes
[XmlRoot(ElementName = "textValue")]
public class TextValue
{
[XmlElement(ElementName = "value")]
public string Value { get; set; }
}
[XmlRoot(ElementName = "text")]
public class Text
{
[XmlElement(ElementName = "textValue")]
public TextValue TextValue { get; set; }
[XmlElement(ElementName = "textStr")]
public string TextStr { get; set; }
[XmlElement(ElementName = "textDate")]
public TextDate TextDate { get; set; }
}
[XmlRoot(ElementName = "variable")]
public class Variable
{
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "text")]
public Text Text { get; set; }
}
[XmlRoot(ElementName = "textDate")]
public class TextDate
{
[XmlElement(ElementName = "date")]
public string Date { get; set; }
}
[XmlRoot(ElementName = "deviceState")]
public class DeviceState
{
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "device")]
public string Device { get; set; }
[XmlElement(ElementName = "variable")]
public List<Variable> Variable { get; set; }
}
code
try
{
DeviceState deserializedXML = new DeviceState();
// Deserialize to object
XmlSerializer serializer = new XmlSerializer(typeof(DeviceState));
using (FileStream stream = File.OpenRead(#"xml.xml"))
{
deserializedXML = (DeviceState)serializer.Deserialize(stream);
// Now get all your IDs
List<string> IDs = (from xml in deserializedXML.Variable select xml.Id).ToList();
} // Put a break-point here, then mouse-over IDs and you will see all your IDs... deserializedXML contains the entire object if you want anythin else ....
}
catch (Exception)
{
throw;
}
I read your XML from a file (xml.xml) that is in the application *.exe folder, you will need to adapt this solution depending on your specific requirements....
Is this what you need?....
try
{
XmlSerializer DeserializerPlaces = new XmlSerializer(typeof(DeviceState));
string html = string.Empty;
string url = #"https://<Your URL>";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
//request.AutomaticDecompression = DecompressionMethods.GZip;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
DeviceState dezerializedXML = (DeviceState)DeserializerPlaces.Deserialize(reader);
//html = reader.ReadToEnd();
}
//Console.WriteLine(html);
}
catch (System.Exception)
{
throw;
}
You would call that every 5 seconds and update your UI (from dezerializedXML properties)

Categories