Convert xls file to xml file using c# - c#

I am a newbie in c#, i have to convert an excel file to an xml with simple nodes. I have done it so far with interop. I have written parts of code to open an xls , close an xls, get value of a cell by Get_range method, and release the object.
But, now i have to output an xml file, i have to goto a particular cell and print a node and a value of a cell. It can be a simple plain text also which i can output or we can use the linq Xelement and Xattributes as well. I think when using get_range:
xlWorkSheet.get_Range("B3", "B3").Value2
i need to print the same in excel.
I am not sure how to do this, please guide me. The resulting xml should look something like this:
<WpData>
<WpType>Design</WpType>
<ReviewType>half</ReviewType>
<References>[1] https:///SysService/SysService_AsrDet/trunk/_doc/20_Design
</References>
<Author>deh</Author>
<Reviewer>abc</Reviewer>
</WpData>
thanks in advance.

You searching for xml serialization. You should define class like this:
[Serializable]
public class WpData
{
public string WpType { get; set; }
public string ReviewType { get; set; }
public string References { get; set; }
public string Author { get; set; }
public string Reviewer { get; set; }
}
Note Serializable attribute on class.
Then you should fill your object from excel data and use XmlSerializer:
WpData xmlSerializibleObject = new WpData();
//....
//here you should fill it from excel based on your data
//And then you can just serialize it to string
string xmlString;
XmlSerializer xmlSerializer = new XmlSerializer(xmlSerializibleObject.GetType());
using(StringWriter textWriter = new StringWriter())
{
xmlSerializer.Serialize(textWriter, xmlSerializibleObject);
xmlString = textWriter.ToString();
}
xmlString will have xml that you need is you fill your object correct from excel.

Related

xmlserialize argumentexception (ArgumentException: Could not cast or convert from System.String to System.Collections.Generic.List`1[System.String].)

Below piece of code is failing and throwing ArgumentException
static void Main(string[] args)
{
string xml = "<root><SourcePatient><Communication>HP:6055550120</Communication></SourcePatient></root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var serializedString = JsonConvert.SerializeXmlNode(doc, Newtonsoft.Json.Formatting.None,true);
var deserialise = serializedString.ToObject<SampleModel>();
}
Models are,
public class SampleModel
{
public SourcePatientModel SourcePatient { get; set; }
}
public class SourcePatientModel
{
public List<string> Communication { get; set; }
}
How to deserialize this? Sometimes Communication node from xml string will have multiple entries
Your current xml is only a single entry
<Communication>HP:6055550120</Communication>
Change your xml input
<Communication><Entry>HP:6055550120</Entry></Communication>
So later when you get multiple entries, they can be processed
<Communication><Entry>HP:6055550120</Entry><Entry>HP:xxxxxxxxx</Entry></Communication>
Your class needs tweaked a bit
if a string [] is acceptable
[XmlArray(ElementName = "Communication")]
[XmlArrayItem(ElementName = "Entry")]
public string[] comm_list // Whatever name you want here
{
get; set;
}
// if you want a list here
// also if your going to do this, realize it creates a new list every time you use it, not the best. (bad practice)
List<string> Communication
{
get => new List<string>(comm_list );
}
otherwise it gets a little complicated
[XmlRoot(ElementName="Communication")]
public class Communication // element name by def
{
[XmlElement(ElementName="Entry")]
public List<string> entry { get; set; }
}
Another possibility, not sure how your multiple entries come in.
If multiple entries look like the following
<Communication>HP:6055550120, HP:7055550120</Communication>
Then you cant have a direct list,
public class SourcePatientModel
{
public string Communication { get; set; }
// which again this creates a list everytime, its better to change your xml to match a tag name for each entry
[XmlIgnore]
public List<string> CommunicationValues { get => Communication.Split(',').ToList();
}
Also this is just typed up code, there may be some typos or compile errors
First I parsed xml to the valid model, then you can convert to json if needed
using (TextReader sr = new StringReader(xml))
{
XmlSerializer serializer = new XmlSerializer(typeof(SampleModel));
var schema = (SampleModel)serializer.Deserialize(sr);
}
[Serializable, XmlRoot("root")]
public class SampleModel
{
public SourcePatientModel SourcePatient { get; set; }
}
public class SourcePatientModel
{
[XmlElement("Communication")]
public List<string> Communication { get; set; }
}
I modified your classes to include some XML serialization attributes. (More on how to figure those out later - the short version is that you don't have to figure it out.)
[XmlRoot(ElementName = "SourcePatient")]
public class SourcePatientModel
{
[XmlElement(ElementName = "Communication")]
public List<string> Communication { get; set; }
}
[XmlRoot(ElementName = "root")]
public class SampleModel
{
[XmlElement(ElementName = "SourcePatient")]
public SourcePatientModel SourcePatientModel { get; set; }
}
...and this code deserializes it:
var serializer = new XmlSerializer(typeof(SampleModel));
using var stringReader = new StringReader(xmlString);
SampleModel deserialized = (SampleModel) serializer.Deserialize(stringReader);
Here's a unit test to make sure a test XML string is deserialized with a list of strings as expected. A unit test is a little easier to run and repeat than a console app. Using them makes writing code a lot easier.
[Test]
public void DeserializationTest()
{
string xmlString = #"
<root>
<SourcePatient>
<Communication>A</Communication>
<Communication>B</Communication>
</SourcePatient>
</root>";
var serializer = new XmlSerializer(typeof(SampleModel));
using var stringReader = new StringReader(xmlString);
SampleModel deserialized = (SampleModel) serializer.Deserialize(stringReader);
Assert.AreEqual(2, deserialized.SourcePatientModel.Communication.Count);
}
Here's a key takeaway: You don't need to memorize XML serialization attributes. I don't bother because I find them confusing. Instead, google "XML to Csharp" and you'll find sites like this one. I pasted your XML into that site and let it generate the classes for me. (Then I renamed them so that they matched your question.)
But be sure that you include enough sample data in your XML so that it can generate the classes for you. I made sure there were two Communication elements so it would create a List<string> in the generated class.
Sites like that might not work for extremely complicated XML, but they work for most scenarios, and it's much easier than figuring out how to write the classes ourselves.

Get tags names from json file as a variable in a class

I am using C# MVC
I am importing a Json file from a location to an Rest API. In order to display the data. the program needs to know the name of the tags.
I would like to know if there is a way to get the tags from the files in an array of strings and declare them via program instead of manually inputting them.
Current C# Code
public class Person
{
public int Id { get; set; }
public int SomeID { get; set; }
public int Number { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
Current Json File:
[{"Id":212,"SomeID":71,"Number":0,"Name":"Mr Jones Mones","Address":"21, street, city"}
So as mentioned this code words fine. But, as I am importing data, the tags may contain different information and I would like to have the public declaration in a way that I can import any file to the API and be able to edit and export it.
Thank you
If you use JSON.net you can parse out json into a JObject then iterate over it's properties like so, however each property value can be any type of object so you'd need to write something to either recursively listed out nested objects or check if values are strings and only take them if they are etc.
var obj = JObject.Parse("{ \"test\": \"test\", \"test1\": \"test1\", \"test2\": \"test2\" }");
foreach (var prop in obj.Properties())
{
Console.WriteLine(prop.Name);
}
You can use JsonConvert like this:
Person person = JsonConvert.DeserializeObject<Person>(jsonString);
Read the docs for JsonConvert for more info.

Generating XML document with C#

I need to generate an XML document that follows this specifictaion
<productName locale="en_GB">Name</productName>
but using XMLSeralization I am getting the following
<productName locale="en_GB">
<Name>Name</Name>
</productName>
My C# code is like this:
[Serializable]
public class productName
{
public productName()
{
}
public string Name;
[XmlAttribute]
public string locale;
}
XmlAttribute is what is required to show the locale in the correct place, but I am unable to figure out how to export the Name field correctly.
Does anyone have an idea?
Thanks
EDIT:
This is the code to generate the XML
public static class XMLSerialize
{
public static void SerializeToXml<T>(string file, T value)
{
var serializer = new XmlSerializer(typeof(T));
using (var writer = XmlWriter.Create(file))
serializer.Serialize(writer, value);
}
public static T DeserializeFromXML<T>(string file)
{
XmlSerializer deserializer = new XmlSerializer(typeof(T));
TextReader textReader = new StreamReader(file);
T result;
result = (T)deserializer.Deserialize(textReader);
textReader.Close();
return result;
}
}
Instead of specifying Name as element specify it as text value by adding [XmlText] attribute
[XmlText]
public string Value { get; set; }
This contains not only a direct answer to your question, but more of a indirect answer of how to solve similar issues like this in the future.
Start the other way around, with your xml, write your xml exactly like you want it and go from there, like this:
// assuming data.xml contains the xml as you'd like it
> xsd.exe data.xml // will generate data.xsd, ie xsd-descriptor
> xsd.exe data.xsd /classes // will generate data.cs, ie c# classes
> notepad.exe data.cs // have a look at data.cs with your favorite editor
Now just have a look at data.cs, this will contain an enormous amount of attributes and stuff and the namespaces are probably wrong, but at least you know how to solve your particular xml-issue.
The direct answer is to use the XmlTextAttribute on the given property, preferably named Value since that is the convention I've seen so far.
[Serializable]
public class productName {
public productName() { }
[XmlText]
public string Value {get; set;}
[XmlAttribute]
public string locale {get; set;}
}

Debugging Reading XML into class in C#

I'm trying make a program to read a simple xml file into my class. I've been using this previous question as a guide: How to Deserialize XML document
The code runs fine with no exceptions, but for some reason, SCArray.ShortCut = null and count is 0. I'm having trouble debugging this because there are no exceptions.
Is there a way to catch this error (i.e., why it's not reading the xml correctly, or what part of my code is causing it to return null results from reading the xml)?
<?xml version="1.0"?>
<ShortCutsArray>
<Shortcut>
<Name>Item1</Name>
<Path>http://www.example1.com</Path>
</Shortcut>
<Shortcut>
<Name>Item2</Name>
<Path>\\Server\example2\ex2.exe</Path>
</Shortcut>
</ShortCutsArray>
The c# code:
class Program
{
public static void Main(string[] args)
{
string shortcuts_file = #"\\server\ShortcutLocation.xml";
ShortCutsArray SCArray = null;
XmlSerializer serializer = new XmlSerializer(typeof(ShortCutsArray));
StreamReader reader = new StreamReader(shortcuts_file);
SCArray = (ShortCutsArray)serializer.Deserialize(reader);
reader.Close();
}
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("ShortCutsArray")]
public class ShortCutsArray
{
[XmlArray("ShortCutsArray")]
[XmlArrayItem("ShotCut", typeof(ShortCut))]
public ShortCut[] ShortCuts { get; set; }
}
[Serializable()]
public class ShortCut
{
[System.Xml.Serialization.XmlElement("Name")]
public string Name { get; set; }
[System.Xml.Serialization.XmlElement("Path")]
public string Path { get; set; }
}
Typo: ShotCut -> Shortcut (note the lower case c - either making the ShortCut class Shortcut or change you xml to be ShortCut would be better)
You've got the root as ShortCutsArray and the XML array name as ShortCutsArray. You'd need the following xml for it to work:
<ShortCutsArray>
<ShortCutsArray>
<Shortcut>
<Name>Item1</Name>
<Path>http://www.example1.com</Path>
</Shortcut>
<Shortcut>
<Name>Item2</Name>
<Path>\\Server\example2\ex2.exe</Path>
</Shortcut>
</ShortCutsArray>
</ShortCutsArray>
I'm not sure its possible to debug this as there's nothing going wrong you've simply found no elements that match due to the above errors.

Deserialize xml which uses attribute name/value pairs

My application receives a constant stream of xml files which are more or less a direct copy of the database record
<record type="update">
<field name="id">987654321</field>
<field name="user_id">4321</field>
<field name="updated">2011-11-24 13:43:23</field>
</record>
And I need to deserialize this into a class which provides nullable property's for all columns
class Record {
public long? Id { get; set; }
public long? UserId { get; set; }
public DateTime? Updated { get; set; }
}
I just cant seem to work out a method of doing this without having to parse the xml file manually and switch on the field's name attribute to store the values.
Is their a way this can be achieved quickly using an XmlSerializer? And if not is their a more efficient way of parsing it manually?
Regards and thanks
My main problem is that the attribute name needs to have its value set to a property name and its value as the contents of a <field>..</field> element
Edit
Edited the answer to reflect the best you can get with your current xml layout you will get an array of field objects with two properties, Name, eg ID, and Value, the text in the node
You can create an Xml Definition class, pass this to an Xml Serializer and it will return you the object with the values of your xml intialised into it's properties.
So given the following definition file.
[XmlTypeAttribute]
[XmlRootAttribute("record")]
public class RecordXmlConfiguration
{
[XmlElementAttribute("field")]
public Field[] Fields { get; set; }
}
[XmlTypeAttribute]
public class Field
{
[XmlAttributeAttribute("name")]
public string Name { get; set; }
[XmlText]
public string Value { get; set; }
}
Then when you have your xml you pass it to a method and it should return you an object of the type of your Xml defintiion class as so
public static object Deserialize(string xml)
{
var deserializer = new System.Xml.Serialization.XmlSerializer(typeof(RecordXmlConfiguration));
using (var reader = XmlReader.Create(new StringReader(xml)))
{
return (RecordXmlConfiguration)deserializer.Deserialize(reader);
}
}
It can be fiddly, but when its set up right it's saved me tonnes of time, as when your done with it you can also create a serialize method in the same maanner to return it to it's Xml form.
make sure to add references to your project to allow for these using statements
using System.Xml.Serialization;
using System.Xml;

Categories