C# has the ability to work with XML in a lot of ways. We’re going to look at a couple of basic situations.
C# allows you to read data from a network source, or from a local file.
Creating a Class to Hold the Data
It helps to have a Class to store the data in. So using the link from before (https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml) we’re going to create a Class that can handle that information.
class CurrencyInfo
{
private string source;
private DateTime lastUpdated;
private string currency;
private double rate;
public CurrencyInfo(string src, DateTime updated, string currency, double conversionRate)
{
this.source = src;
this.lastUpdated = updated;
this.currency = currency;
this.rate = conversionRate;
}
override public string ToString()
{
string s = "Data Source: " + this.source + "\n"
+ "Last Updated: " + this.lastUpdated.ToShortDateString() + "\n"
+ "Currency: " + this.currency + "\n"
+ "Conversion Rate: " + this.rate;
return s;
}
}
Loading Network Data
In order to load the XML, we’re going to create an XML document, and then load the data from the URI
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
Next we’re going to read a couple of pieces of information from the XML file. Notice how we are going to read in both a node value and an attribute from a node.
// reading in the text of a node
string source = xmlDoc.DocumentElement.ChildNodes[1].ChildNodes[0].ChildNodes[0].InnerText;
// reading in a value of a node
string myDate = xmlDoc.DocumentElement.ChildNodes[2].ChildNodes[0].Attributes["time"].Value;
DateTime updated = new DateTime(Convert.ToInt32(myDate.Split("-")[0]),
Convert.ToInt32(myDate.Split("-")[1]), Convert.ToInt32(myDate.Split("-")[2]));
For simplicity sake, we’re using strings for both of the variables as that is how it is stored in the XML file. We then have to convert the data into the correct data format.
Notice how we know the XML path to get to it, and we’re following that path to get the information we want.
Reading through the XML data can be done with a foreach loop since we won’t know how many nodes there will necessarily be.
foreach (XmlNode xmlNode in xmlDoc.DocumentElement.ChildNodes[2].ChildNodes[0].ChildNodes)
{
ci = new CurrencyInfo(source, updated, xmlNode.Attributes["currency"].Value,
Convert.ToDouble(xmlNode.Attributes["rate"].Value));
Console.WriteLine(ci.ToString());
}
Storing Data without an Object
Simple data like this, is most useful when you want to read in data and use it based upon a lookup, such as might be found with a dictionary object.
IDictionary<string,double> dictionary = new Dictionary<string, double>();
foreach (XmlNode xmlNode in xmlDoc.DocumentElement.ChildNodes[2].ChildNodes[0].ChildNodes)
{
dictionary.Add(xmlNode.Attributes["currency"].Value,
Convert.ToDouble(xmlNode.Attributes["rate"].Value));
}
Notice how instead of the object we created, we add it to a dictionary object, and pass in the key and value data. At that point, we can then use the data anywhere we need to in our application where the dictionary is available.
This means we can give is a key node, such as USD, or AUS, and find the conversion rate easily.
To loop through them all, we use another foreach loop as it is the simplest method in this case.
foreach (KeyValuePair<string, double> kvp in dictionary)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
}
Writing Data to a Local File
In this case, we still need to have an Class that we can use. We’ll create a simple Customer class.
public class Customer
{
public string FirstName;
public string LastName;
}
For simplicity sake, I just created two public properties.
We’ll create a couple of Customer objects.
// Create an instance of the CustomerData class and populate
// it with the data from the form.
Customer customer = new Customer();
customer.FirstName = "John";
customer.LastName = "Smith";
Customer customer2 = new Customer();
customer2.FirstName = "Mary";
customer2.LastName = "Jones";
Now we will create a XMLSerializer to create the XML data, and use a FileStream object to write it.
// Create and XmlSerializer to serialize the data to a file
XmlSerializer xs = new XmlSerializer(typeof(Customer));
using (FileStream fs = new FileStream("Data.xml", FileMode.Create))
{
xs.Serialize(fs, customer);
xs.Serialize(fs, customer2);
}
Finally, within the using braces, we call the XmlSerializer object to create the stream. However, you’ll notice an issue. That is you don’t want to call Serialize more than once, as it creates the header multiple times.
Therefore, we will need to either create an array of objects, or a special class which can hold multiple customer objects.
Customer[] customers = new Customer[2] { customer, customer2 };
// Create and XmlSerializer to serialize the data to a file
XmlSerializer xs = new XmlSerializer(typeof(Customer[]));
using (FileStream fs = new FileStream("Data.xml", FileMode.Create))
{
xs.Serialize(fs, customers);
}
Or, using another class:
public class CustomerList
{
public Customer[] customers = new Customer[2];
}
Then we can pass in the data as we need to, so we can create a single XML file.
CustomerList cl = new CustomerList();
cl.customers[0] = customer;
cl.customers[1] = customer2;
// Create and XmlSerializer to serialize the data to a file
XmlSerializer xs = new XmlSerializer(typeof(CustomerList));
using (FileStream fs = new FileStream("Data.xml", FileMode.Create))
{
xs.Serialize(fs, cl);
}
Working with XML in C# was originally found on Access 2 Learn