Writing XML Files in C#? - c#

How would I go about doing this:
for( var i = 0; i < emp; i++ )
{
Console.WriteLine("Name: ");
var name = Console.ReadLine();
Console.WriteLine("Nationality:");
var country = Console.ReadLine();
employeeList.Add( new Employee(){
Name = name,
Nationality = country
} );
}
I want a test run of, for example:
Imran Khan
Pakistani
to generate an XML File:
<employee>
<name> Imran Khan </name>
<nationality> Pakistani </nationality>
</employee>
Any suggestions?

My suggestion is to use xml serialization:
[XmlRoot("employee")]
public class Employee {
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("nationality")]
public string Nationality { get; set; }
}
void Main() {
// ...
var serializer = new XmlSerializer(typeof(Employee));
var emp = new Employee { /* properties... */ };
using (var output = /* open a Stream or a StringWriter for output */) {
serializer.Serialize(output, emp);
}
}

There are several ways, but the one I like is using the class XDocument.
Here's a nice example on how to do it.
How can I build XML in C#?
If you have any questions, just ask.

To give you an idea of how XDocument works based on your loop, you would do this:
XDocument xdoc = new XDocument();
xdoc.Add(new XElement("employees"));
for (var i = 0; i < 3; i++)
{
Console.WriteLine("Name: ");
var name = Console.ReadLine();
Console.WriteLine("Nationality:");
var country = Console.ReadLine();
XElement el = new XElement("employee");
el.Add(new XElement("name", name), new XElement("country", country));
xdoc.Element("employees").Add(el);
}
After running, xdoc would be something like:
<employees>
<employee>
<name>bob</name>
<country>us</country>
</employee>
<employee>
<name>jess</name>
<country>us</country>
</employee>
</employees>

<employee>
<name> Imran Khan </name>
<nationality> Pakistani </nationality>
</employee>
XElement x = new XElement ("employee",new XElement("name",e.name),new XElement("nationality",e.nationality) );

Related

c# Generate XML document based on Xpath

I need to create an XML document like this:
<Root>
<Data>
<Name>Name1</Name>
<Surname>Surname1</Surname>
<Gender>M</Gender>
</Data>
<Data>
<Name>Name2</Name>
<Surname>Surname2</Surname>
<Gender>F</Gender>
</Data>
</Root>
I've got the Xpath of the XML Elements, so I've create the following class
class XpathFieldValue
{
public string Xpath { get; set; }
public string Value { get; set; }
}
and then the following method
public static void CreateXml()
{
List<XpathFieldValue> fieldValues = new List<XpathFieldValue> {
new XpathFieldValue{ Xpath="/Root/Data/Name", Value="Name1" },
new XpathFieldValue{ Xpath="/Root/Data/Surname", Value="Surname1" },
new XpathFieldValue{ Xpath="/Root/Data/Gender", Value="M"},
new XpathFieldValue{ Xpath="/Root/Data/Name", Value="Name2" },
new XpathFieldValue{ Xpath="/Root/Data/Surname", Value="Surname2" },
new XpathFieldValue{ Xpath="/Root/Data/Gender", Value="F"}
};
XmlDocument document = new XmlDocument();
document.LoadXml("<Root/>");
foreach (XpathFieldValue fieldValue in fieldValues)
{
Set(document, fieldValue.Xpath, fieldValue.Value);
}
document.Save(#"C:\Temp\xmlDocOut.xml");
}
I've copyed the Set method from here: link
But when I run it it creates only the last parth of XML
<Root>
<Data>
<Name>Name2</Name>
<Surname>Surname2</Surname>
<Gender>F</Gender>
</Data>
</Root>
Can anyone help me?
XPath isn't really intended to generate documents but to access em.
Another (probably better) approach would be to serialize it.
But, since the question requires the fields of xml to be variable, serialization isn't a viable way. i STRONGLY advise you to change this requirement and you'll see why in the following example:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
using (var writer = new System.IO.StreamWriter(#"C:\Users\luigi.trabacchin\Desktop\asd.xml"))
{
var doc = new System.Xml.XmlDocument();
var root = doc.CreateElement("Root");
doc.AppendChild(root);
for (var i = 0; i <= 1; i++)
{
var dataNode = doc.CreateElement("Data");
root.AppendChild(dataNode);
{
var node = doc.CreateElement("Name");
dataNode.AppendChild(node);
var text = doc.CreateTextNode($"Name {i}");
node.AppendChild(text);
}
{
var node = doc.CreateElement("Surname");
dataNode.AppendChild(node);
var text = doc.CreateTextNode($"Surname {i}");
node.AppendChild(text);
}
{
var node = doc.CreateElement("Gender");
dataNode.AppendChild(node);
var text = doc.CreateTextNode(i %2 == 0 ? "M" : "F");
node.AppendChild(text);
}
}
doc.Save(writer);
}
Console.WriteLine("Hello World!");
}
}
}
It quickly becomes very tedious and hard to work with.
Still i hope this answer your question.
Next time, maybe, state all the requirements directly in the question!

Merge two XML files in C# where the tags ID is the same

I need to merge two XML files in C# where AccountNumber is the same in these XMLfiles.
I have about 400 accounts in the XML file.
XML 1:
<?xml version="1.0" standalone="yes"?>
<Account>
<Table1>
<Id>12</Id>
<AccountNumber>5050</AccountNumber>
<External>false</External>
</Table1>
</Account>
XML 2:
<?xml version="1.0" standalone="yes"?>
<Account>
<Table1>
<AccountNumber>5050</AccountNumber>
<ProductDate>2017-12-18</ProductDate>
<ProductNr>294</ProductNr>
</Table1>
</Account>
Så the result will be like this
XML 3:
<?xml version="1.0" standalone="yes"?>
<Account>
<Table1>
<Id>12</Id>
<AccountNumber>5050</AccountNumber>
<External>false</External>
<ProductDate>2017-12-18</ProductDate>
<ProductNr>294</ProductNr>
</Table1>
</Account>
You can use this:
public class XmlMatcher
{
public XDocument MatchXmlFiles(XDocument doc1, XDocument doc2)
{
XDocument result = new XDocument();
List<XElement> doc1Elements = doc1.Root.Elements().ToList();
List<XElement> doc2Elements = doc2.Root.Elements().ToList();
XElement accountElement = new XElement("Account");
result = new XDocument(accountElement);
for (int i = 0; i < doc1Elements.Count(); i++)
{
XmlDocument subDoc = new XmlDocument();
subDoc.LoadXml(doc1Elements[i].ToString());
string tableName = subDoc.FirstChild.Name;
string accountNumber = doc1Elements[i].Elements().Where(x => x.Name == "AccountNumber").FirstOrDefault().Value;
List<XElement> doc1Childs = doc1Elements[i].Elements().ToList();
List<XElement> doc2Childs = doc2Elements.Where(x => x.ToString().IndexOf(accountNumber) > -1).FirstOrDefault().Elements().ToList();
XElement tblElement = new XElement(tableName);
tblElement.Add(new XElement("Id" , GetChildValue(doc1Childs, doc2Childs, "Id")));
tblElement.Add(new XElement("AccountNumber", accountNumber));
tblElement.Add(new XElement("External" , GetChildValue(doc1Childs, doc2Childs, "External")));
tblElement.Add(new XElement("ProductDate" , GetChildValue(doc1Childs, doc2Childs, "ProductDate")));
tblElement.Add(new XElement("ProductNr" , GetChildValue(doc1Childs, doc2Childs, "ProductNr")));
accountElement.Add(tblElement);
}
return result;
}
public object GetChildValue(List<XElement> doc1Childs, List<XElement> doc2Childs, string name)
{
object value = string.Empty;
XElement child = doc1Childs.Where(x => x.Name == name).FirstOrDefault();
if (child != null)
{
value = child.Value;
}
else
{
child = doc2Childs.Where(x => x.Name == name).FirstOrDefault();
if(child != null)
value = child.Value;
}
return value;
}
}
Usage:
XmlMatcher xmlManager = new XmlMatcher();
XDocument xml1 = XDocument.Load("Your Xm1 Path");
XDocument xml2 = XDocument.Load("Your Xm2 Path");
XDocument xml3 = xmlManager.MatchXmlFiles(xml1, xml2);
xml3.Save("Your Xm3 Path");

How would I parse an XML file into a list

List:
List<string> list = new List<string>();
XML File:
<memberlist>
<member>
<name>Name</name>
<status>Status</status>
</member>
</memberlist>
How would I go about parsing this file, lets say (file.xml) into the list?
I've tried many ways but none of them seem to be working.
I want to check to see if the status is 'gold', and if it is, I would like to put the name of that member into the list.
Load the xml into an XDocument. You can do this from a file, I have demonstrated from a string.
Do a linq query for elements named "status" (within "member") that also have a value of "gold".
Of those, grab the value of the "name" element.
Use AddRange on your list of strings.
List<string> lstGolds = new List<string>();
string xml ="<memberlist><member><name>Name</name><status>gold</status></member></memberlist>";
XDocument doc = XDocument.Parse(xml);
var goldStatus = doc.Descendants("member")
.Where(d => d.Element("status").Value == "gold")
.Select(d => d.Element("name").Value);
lstGolds.AddRange(goldStatus);
You should use using System.Xml.Linq;
using (FileStream fileStramWrite = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (StreamReader streamReader = new StreamReader(fileStramWrite))
{
var xdoc = XDocument.Load(streamReader);
var xElement = xdoc.Element("memberlist");
var xElement2 = xElement.Element("member");
var name = xElement2.Element("name").Value;
var status = xElement2.Element("status").Value;
}
Convert your XML to a list of objects....
Use these two mehods:
public static string Serialize<T>(T dataToSerialize)
{
try
{
var stringwriter = new ISOEncodingStringWriter();
var serializer = new XmlSerializer(typeof(T));
var xns = new XmlSerializerNamespaces();
xns.Add(string.Empty, string.Empty);
serializer.Serialize(stringwriter, dataToSerialize, xns);
return stringwriter.ToString();
}
catch
{
throw;
}
}
public static T Deserialize<T>(string xmlText)
{
try
{
var stringReader = new System.IO.StringReader(xmlText);
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
catch
{
throw;
}
}
Make the following Class where you give the following attributes
[XmlRoot(ElementName = "Members", Namespace = "")]
public class Members
{
[XmlElement("Member")]
public Member[] member { get; set; }
}
public class Member
{
[XmlElementAttribute("Name")]
public string Name { get; set; }
[XmlElementAttribute("Status")]
public string Status { get; set; }
}
Then deserialize your data.
Members result = Deserialize<Members>(XML_String);
You got your members in a array and you ca convert that to a list if you want.
You can use LINQ
XElement xml = XElement.Load("locationToYourXmlFile");
var members = xml.Elements("member");
var list = members.Where(member => member.Element("status")?.Value == "Gold")
.Select(member => member.Element("name")?.Value)
.ToList();
Assuming your XML has a bunch of member elements under the root memberlist element, each with a name and status element inside that.
<?xml version="1.0" encoding="utf-8"?>
<memberlist>
<member>
<name>John</name>
<status>Gold</status>
</member>
<member>
<name>Sam</name>
<status>Silver</status>
</member>
<member>
<name>Sara</name>
<status>Gold</status>
</member>
</memberlist>

List of object array from XML

I have a xml that looks like this
<?xml version="1.0" encoding="utf-8" ?>
<Resorces>
<Resource id="3" name="loreum ipsum" downloadcount="5"></Resource>
<Resource id="2" name="loreum ipsum" downloadcount="9"></Resource>
</Resorces>
I have a class
public class Report
{
public int ResourceId {get; set; }
public string ResourceName { get; set; }
public int DownloadCount { get; set; }
}
I want to convert that xml into list of Report objects
I tried the below code
var resourceList = doc.Descendants("Resorces")
.First()
.Elements("Resource")
.ToList();
I get values like this,
How can I get it as list of objects?
Basically what you are missing is the part where you convert the Xml objects into your defined object of Report. This is how you can do it:
var resourceList = doc.Descendants("Resorces")
.First()
.Elements("Resource")
.Select(element => new Report()
{
ResourceId = (int)element.Attribute("id"),
ResourceName = (string)element.Attribute("name"),
DownloadCount = (int)element.Attribute("downloadcount")
})
.ToList();
I kept here the previous linq methods you called to keep it close to the original but as others said you can just get the Elements("Resource") from the doc root
XmlDocument newdoc = new XmlDocument();
newdoc.InnerXml = " <?xml version="1.0" encoding="utf-8" ?>
<Resorces>
<Resource id="3" name="loreum ipsum" downloadcount="5"></Resource>
<Resource id="2" name="loreum ipsum" downloadcount="9"></Resource>
</Resorces>";
List<string> list = new List <string>();
var selectnode = "Resorces/Resource";
var nodes = newdoc.SelectNodes(selectnode);
foreach (XmlNode nod in nodes)
{
string id = nod["id"].InnerText;
string name = nod["name"].InnerText;
string downloadcount = nod["downloadcount"].InnerText;
list.Add(id);
list.Add(name);
list.Add(downloadcount);
}
Console.WriteLine(list.Count);
You could use Elements method to get elements for a given element name.
XDocument doc = XDocument.Load(filepath);
var result = doc.Root
.Elements("Resource")
.Select(x=> new Report()
{
ResourceId = int.Parse( x.Attribute("id").Value),
ResourceName = (string)x.Attribute("name").Value,
DownloadCount = int.Parse( x.Attribute("downloadcount").Value)
})
.ToList();
Check this Demo
You can get by this
XDocument doc = XDocument.Load(xmlpath);
List<Report> resourceList = doc.Descendants("Resorces")
.First()
.Elements("Resource")
.Select(report => new Report()
{
ResourceId = (int)report.Attribute("id"),
ResourceName = (string)report.Attribute("name"),
DownloadCount = (int)report.Attribute("downloadcount")
}).ToList();

XML Parse to list

[XmlRoot("Employees")]
public class Employee
{
[XmlElement("EmpId")]
public int Id { get; set; }
[XmlElement("Name")]
public string Name { get; set; }
}
and simple method, which return List:
public static List<Employee> SampleData()
{
return new List<Employee>()
{
new Employee(){
Id = 1,
Name = "pierwszy"
},
new Employee(){
Id = 2,
Name = "drugi"
},
new Employee(){
Id = 3,
Name = "trzeci"
}
};
}
Program.cs:
var list = Employee.SampleData();
XmlSerializer ser = new XmlSerializer(typeof(List<Employee>));
TextWriter writer = new StreamWriter("nowi.xml");
ser.Serialize(writer, list);
I have file result:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEmployee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Employee>
<EmpId>1</EmpId>
<Name>pierwszy</Name>
</Employee>
<Employee>
<EmpId>2</EmpId>
<Name>drugi</Name>
</Employee>
<Employee>
<EmpId>3</EmpId>
<Name>trzeci</Name>
</Employee>
</ArrayOfEmployee>
but i would like for Root Element has name: "Employees", not "ArrayOfEmployee"
how can i make it?
I want to do it, because i have file, where structure looks like:
<Employees>
<Employee>
...
</Employee>
<Employee>
...
</Employee>
</Employees>
Just change as below
XmlSerializer ser = new XmlSerializer(typeof(List<Employee>),
new XmlRootAttribute("Employees"));
that's all. But to get a clean xml as in your question (no xml declaration, no xsi or xsd namespaces etc.), you should use a few tricks
XmlSerializer ser = new XmlSerializer(typeof(List<Employee>),
new XmlRootAttribute("Employees"));
TextWriter writer = new StreamWriter(filename);
var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings() { OmitXmlDeclaration = true, Indent = true });
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
ser.Serialize(xmlWriter, list, ns);
You can pass the XmlRootAttribute to set the element Name:
var root = new XmlRootAttribute("Employees");
XmlSerializer ser = new XmlSerializer(typeof(List<Employee>), root);
TextWriter writer = new StreamWriter("nowi.xml");
ser.Serialize(writer, list);
From http://msdn.microsoft.com/en-us/library/f1wczcys%28v=vs.110%29.aspx :
... the root parameter allows you to replace the default object's
information by specifying an XmlRootAttribute; the object allows you
to set a different namespace, element name, and so on.
You can mark your property with attributes, use the XmlArray and XmlArrayItem attribute

Categories