Skip to main content
.NET

How to use XML with C# – A beginner guide for basic XML operations in .NET

Christian Schou

How can we use XML with C#? Let’s start off with what is XML? It is short for eXtensible Markup Language. It is a simple text-based format for representing structured data/information. XML is used in documents, data, configurations, books, transactions, invoices, purchase orders, orders, communication between applications, etc…

It is a very commonly used language for transferring data between applications. Primarily I use it to store configurations and to transfer order data like purchase orders, orders, invoices, etc… between API’s. In this tutorial, I will show you some basics of how to work with XML in C#.

When you are done reading this article you will have knowledge of how to serialize (convert the object to XML), deserialize (convert XML to object) and query XML (select a specific part of XML) using C#. We will be building a console application running .NET 5.0 to handle our XML operations. If you are ready, then let’s get started.

Introduction

Before we start to make some code and work with object de- and serialization, I want to give you a short introduction to XML. Maybe you already know some of it, else it is good repetition. Here is an example of a XML file:

<note>
  <date>2022-03-05</date>
  <hour>07:30</hour>
  <to>Christian</to>
  <from>Nicoline</from>
  <body>Don't forget to feed Kenya!</body>
</note>

What is XML?

XML is a software- and hardware-independent tool for storing and transporting data. It is designed to be self-descriptive + transfer- and store data. If you know HTML you will have an easy time understanding XML as XML is also a markup language. XML is recommended by W3C since February 1998.

Does XML use predefined tags?

XML has NO predefined tags. You are free to write whatever you would like inside an XML file. If you see any tags inside an XML file like the one I have shoved above, they have not been defined in any XML standard. Those are tags I created/invented myself. Actually, they are made up of my object inside a project. If you are familiar with HTML you already know that HTML requires som predefined tags like p, h1, h2, table, div, etc… With XML, you are the author and must define both the tags and document structure. There are no limits or rules.

Is XML extensible?

The great thing about XML is that most applications consuming XML will still work as expected if new data is added (or perhaps removed). If I added or removed a part of the XML file above, my objects would still continue to work, but the value would be NULL in the application. This makes XML a great choice when choosing a media to transfer data or store settings inside.

Getting started at XML with C#

When you first get to know XML inside C# a little, you will quickly discover that XDocument and XElement are the main classes for handling XML in .NET.

  • XDocument is responsible for representing a complete and valid XML document.
  • XElement is responsible for representing XML elements.

LINQ to XML queries is also a popular tool. They allow us to extract specific data from a part of the XML document to a variable at runtime. If you would like to see the source code, you can skip to the end of the article. There you will find a reference to the GitHub Repository.

Build XML using plain code

Alright – let’s create a very basic XML example using plain code in C#. I have created a new Console Application running .NET 5.0 in Visual Studio (for MAC – hence the layout for Visual Studio in the pictures throughout this article).

using System;
using System.Xml.Linq;

namespace XMLBasics
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(XmlUsingPlainCode());
        }

        static XDocument XmlUsingPlainCode()
        {
            XDocument document = new XDocument
                (
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XComment("XML from plain code"),
                    new XElement("Courses")
                );

            return document;
        }
    }
}

Let’s spin it up and see the output:

xml from c# code
Simple XML from code

Woohoo! It works and as you can see it is very easy to generate XML using XDocument in C#. Let’s add some courses to our code and check the output. Below code is only the code inside the method named XmlUsingPlainCode:

static XDocument XmlUsingPlainCode()
{
    XDocument document = new XDocument
        (
            new XDeclaration("1.0", "utf-8", "yes"),
            new XComment("XML from plain code"),
            
            new XElement("Courses",
                new XElement("Course",
                    new XElement("Title", "XML Basics"),
                    new XElement("Duration", "15 min"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free")),
                new XElement("Course",
                    new XElement("Title", ".NET Core for Beginners"),
                    new XElement("Duration", "10 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free")))
        );

    return document;
}

XElement allows us to initialize a new instance of XElement inside XElement. This provides a way for us to add multiple elements under each element. By doing this we can easily create a document with a specific structure.

Let’s spin it up and see our new updated XML in action:

<!--XML from plain code-->
<Courses>
  <Course>
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price>Free</Price>
  </Course>
  <Course>
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price>Free</Price>
  </Course>
</Courses>

Bam – we now have a list of courses in XML generated from plain C# code. Perfect! Have you ever heard about attributes? Let’s include them in the course details to give a bit more accurate information about some of our elements.

Using XAttribute to give more detailed information about elements

Attributes are a great way to include additional information on an element. Below is an updated version of our code that will add attributes to some elements.

static XDocument XmlUsingPlainCode()
{
    XDocument document = new XDocument
        (
            new XDeclaration("1.0", "utf-8", "yes"),
            new XComment("XML from plain code"),
            
            new XElement("Courses",
                new XElement("Course",
                    new XAttribute("Id", 1),
                    new XElement("Title", "XML Basics"),
                    new XElement("Duration", "15 min"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency","USD"))),
                new XElement("Course",
                    new XAttribute("Id", 2),
                    new XElement("Title", ".NET Core for Beginners"),
                    new XElement("Duration", "10 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency", "DKK"))))
        );

    return document;
}

Under each XElement, we can initialize a new XAttribute almost the same way as we did with our elements. Let’s run the application and check the output:

<!--XML from plain code-->
<Courses>
  <Course Id="1">
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">Free</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
</Courses>

Great – it’s beginning to look like something we can use for a real application!

Save XML to File

XDocument got a built-in method that allows us to save an XML file easily. Often our XML files have to be written to a local share if they contain configurations or data that should be picked up by other applications. Let’s see how we can save a copy of our XML data to a local file using C#.

If you are using Windows, you can append “@” at the beginning of your string to escape the backslashes “\” for the path.

static void Main(string[] args)
{
    XDocument xmlFromPlainCode = XmlUsingPlainCode();

    xmlFromPlainCode.Save("/Users/christianschou/Desktop/xmlFromPlainCode.xml");

    Console.WriteLine(xmlFromPlainCode);
}

You have to use the Save() method with the path for where the document should be saved. The Save() method takes an overload for save options. Here you can specify if you would disable the formatting of the document. (I have never done it myself, but the option is there).

As you probably noticed I have changed the Console.WriteLine to use the data from a variable instead of calling the method inside Console.WriteLine. This is because we would like to use the XDocument generated by the method XMLUsingPlainCode() multiple times.

The result:

xml output from c#, terminal, macos
The XML file has been saved and here outputted to the terminal to show contents

Load XML from File

Now that we have an XML file, let’s load it into our application and read the contents of the file. Below is the code you would need for the console application to load an XML file with C#.

static void Main(string[] args)
{
    string xmlDocPath = "/Users/christianschou/Desktop/xmlFromPlainCode.xml";

    // Generate XML document and save to disk
    XDocument xmlFromPlainCode = XmlUsingPlainCode();
    xmlFromPlainCode.Save(xmlDocPath);

    // Load generated XML document from disk
    XDocument loadedDocument = XDocument.Load(xmlDocPath);

    // Console Output for demo
    Console.WriteLine("------ # Generated XML from code # ------");
    Console.WriteLine(xmlFromPlainCode);
    Console.WriteLine();
    Console.WriteLine("------ # Loaded XML Document # ------");
    Console.WriteLine(loadedDocument);
}

In the code above I have moved the path of the document to a string variable because I don’t want to be typing the same path multiple times. Then I divided the save, load, and console writing into “sections” for easier understanding.

As you can see we start off by saving the XML code into a file, then we load that same file and write the content into the console under a “header” in the console. The output looks like the following:

------ # Generated XML from code # ------
<!--XML from plain code-->
<Courses>
  <Course Id="1">
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">Free</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
</Courses>

------ # Loaded XML Document # ------
<!--XML from plain code-->
<Courses>
  <Course Id="1">
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">Free</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
</Courses>

Great, now we are able to load in XML documents inside of our C# application. Let’s move on and make a query on the loaded document.

Using LINQ to Query XML documents in C#

LINQ is a uniform query syntax in C# to retrieve data from different sources and formats, which makes it ideal to use if we would like some specific data in the XML document.

Let’s make a query to get all course elements from the document and print out the details in the console. To make it even better, I have added one more course to the plain code method with an actual price for the course. This is used when showing details for the courses in the console. Below is the method XmlUsingPlainCode() with the extra course added.

static XDocument XmlUsingPlainCode()
{
    XDocument document = new XDocument
        (
            new XDeclaration("1.0", "utf-8", "yes"),
            new XComment("XML from plain code"),

            new XElement("Courses",
                // Free Course
                new XElement("Course",
                    new XAttribute("Id", 1),
                    new XElement("Title", "XML Basics"),
                    new XElement("Duration", "15 min"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency", "USD"))),

                // Paid Course
                new XElement("Course",
                    new XAttribute("Id", 2),
                    new XElement("Title", "Advanced MS SQL Queries"),
                    new XElement("Duration", "15 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", 12.95,
                        new XAttribute("Currency", "EUR"))),

                // Free Course
                new XElement("Course",
                    new XAttribute("Id", 2),
                    new XElement("Title", ".NET Core for Beginners"),
                    new XElement("Duration", "10 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency", "DKK"))))
        );

    return document;
}

So now that we have the updated method to add a course with an actual price, let’s create a new method named PerformLinqQueryOnXml(string docPath) and run a LINQ query on the loaded document.

static void PerformLinqQueryOnXml(string docPath)
{
    XElement document = XElement.Load(docPath); // Load document as an XML Element

    var amountOfCourses = document.Elements("Course"); // Get the course elements into an enumerator

    Console.WriteLine("------ # Extract Courses In Document Using LINQ# ------\n");

    // Write out each course details to the console
    foreach (var course in amountOfCourses)
    {
        Console.WriteLine("### Course Details ###");
        Console.WriteLine($"Course: {course.Element("Title").Value}");
        Console.WriteLine($"Duration: {course.Element("Duration").Value}");
        Console.WriteLine($"Instructor: {course.Element("Instructor").Value}");

        if (course.Element("Price").Value == "Free")
        {
            Console.WriteLine($"Price: It's a free course\n");
        }
        else
        {
            Console.WriteLine($"Price: {course.Element("Price").Attribute("Currency").Value} {course.Element("Price").Value}\n");
        }
    }
}

Let’s also update our Main method to use the new classes and clean it up a little with some new line commands at the end of our write lines.

static void Main(string[] args)
{
    string xmlDocPath = "/Users/christianschou/Desktop/xmlFromPlainCode.xml";

    // Generate XML document and save to disk
    XDocument xmlFromPlainCode = XmlUsingPlainCode();
    xmlFromPlainCode.Save(xmlDocPath);

    // Load generated XML document from disk
    XDocument loadedDocument = XDocument.Load(xmlDocPath);

    // Console Output for demo
    Console.WriteLine("------ # Generated XML from code # ------\n");
    Console.WriteLine(xmlFromPlainCode + "\n");
    Console.WriteLine("------ # Loaded XML Document # ------\n");
    Console.WriteLine(loadedDocument + "\n");
            
    PerformLinqQueryOnXml(xmlDocPath);
}

Now for the exciting part. Run the application and check the output. You should receive an output like this in your console:

------ # Generated XML from code # ------

<!--XML from plain code-->
<Courses>
  <Course Id="1">
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">Free</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="EUR">12.95</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
</Courses>

------ # Loaded XML Document # ------

<!--XML from plain code-->
<Courses>
  <Course Id="1">
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">Free</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="EUR">12.95</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
</Courses>

------ # Extract Courses In Document Using LINQ# ------

### Course Details ###
Course: XML Basics
Duration: 15 min
Instructor: Christian Schou
Price: It is a free course

### Course Details ###
Course: .NET Core for Beginners
Duration: 10 hours
Instructor: Christian Schou
Price: EUR 12.95

### Course Details ###
Course: .NET Core for Beginners
Duration: 10 hours
Instructor: Christian Schou
Price: It is a free course

That’s all you have to do to query out data from XML with C#. Easy job, right?!

Build XML using objects (Serialize XML)

When we are serializing objects we take the current state of an object and persist it in some way. Because we use the .NET framework we got some powerful tools to serialize any object to XML. The only namespace you have to use is System.Xml.Serialization, it got all the capabilities for the serialization process.

For this to work, I have created a new folder named Models. Inside that folder, I have added 3 new classed named:

  • Courses.cs
  • Course.cs
  • Price.cs

Below are each class with its fields:

Courses.cs

using System.Collections.Generic;
using System.Xml.Serialization;

namespace XMLBasics.Models
{
    [XmlRoot("Courses")]
    public class Courses
    {
        [XmlElement(ElementName = "Academy")]
        public string Academy { get; set; }

        [XmlElement(ElementName = "Course")]
        public List<Course> CourseList { get; set; }

        public Courses()
        {
            CourseList = new List<Course>();
        }
    }
}

Course.cs

using System.Xml.Serialization;

namespace XMLBasics.Models
{
    [XmlRoot(ElementName = "Course")]
    public class Course
    {
    [XmlElement(ElementName = "Title")]
    public string Title { get; set; }

    [XmlElement(ElementName = "Duration")]
    public string Duration { get; set; }

    [XmlElement(ElementName = "Instructor")]
    public string Instructor { get; set; }

    [XmlElement(ElementName = "Price")]
    public Price Price { get; set; }

    [XmlAttribute(AttributeName = "Id")]
    public int Id { get; set; }

    [XmlText]
    public string Text { get; set; }

        public Course()
        {
        Price = new Price();
        }
    }
}

Price.cs

using System.Xml.Serialization;

namespace XMLBasics.Models
{
    [XmlRoot(ElementName = "Price")]
    public class Price
    {
        [XmlAttribute(AttributeName = "Currency")]
        public string Currency { get; set; }

        [XmlText]
        public string Text { get; set; }
    }
}

On each field, in my models, I have specified XML attributes. As you can see they got different names as I want them to behave differently when serializing the objects to XML. I always start out telling what my XML root is with an element name. You can name the model something and then change its name at serialization time. I then specify all elements under that specific property in the document and finally the attribute and eventually text on the root property.

Now we have to create some new objects and put them in a list. This list will then be converted into XML using the System.Xml.Serialization library. In Program.cs create a new static void method named SerializeToXml() with the following code:

static string SerializeToXml()
{
    string instructor = "Christian Schou";
    int i = 1;
    Random rand = new Random();

    // Create some courses
    Courses courses = new Courses { Academy = "Coding with Christian Schou",
        CourseList = new List<Course> {
            new Course
            {
                Title = "How to get started with MailKit",
                Duration = $"{rand.Next(1, 5)} hours and {rand.Next(0, 60)} minutes",
                Instructor = instructor,
                Price = new Price { Currency = "DKK", Text = "Free" }
            },
            new Course
            {
                Title = "Dapper with repository in ASP.NET",
                Duration = $"{rand.Next(1, 5)} hours and {rand.Next(0, 60)} minutes",
                Instructor = instructor,
                Price = new Price { Currency = "EUR", Text = "Free" }
            },
            new Course
            {
                Title = "How to create a WEB API",
                Duration = $"{rand.Next(1, 5)} hours and {rand.Next(0, 60)} minutes",
                Instructor = instructor,
                Price = new Price { Currency = "USD", Text = "19.95" }
            }
        }
    };

    // Set ID on each Course

    foreach (var course in courses.CourseList)
    {
        course.Id = i++;
    }

    XmlSerializer x = new XmlSerializer(courses.GetType()); // Get the exact runtime type of the current instance
    StringBuilder output = new StringBuilder();
    var writer = new StringWriter(output);
    x.Serialize(writer, courses);

    return output.ToString();

}

This method will generate the console lines to identify the data at runtime. As you can see, I have added three courses as objects and added them to the list named coursesbased on my Courses.cs model.

For each course, I would like to supply an ID. This can be done in multiple ways, but a method is a simple foreach loop like the one I have created above. It simply takes each course and updates the ID with the number the course got on the list.

Then I initialize a new instance of XmlSerializer where I specify the type of the list with courses. Finally, I serialize the content using the XmlSerializer instance. Here I specify the text writer and my course’s object. Let’s add it to the Main method and run the application.

static void Main(string[] args)
{
    string xmlDocPath = "/Users/christianschou/Desktop/xmlFromPlainCode.xml";

    // Generate XML document and save to disk
    XDocument xmlFromPlainCode = XmlUsingPlainCode();
    xmlFromPlainCode.Save(xmlDocPath);

    // Load generated XML document from disk
    XDocument loadedDocument = XDocument.Load(xmlDocPath);

    // Console Output for demo
    Console.WriteLine("------ # Generated XML from code # ------\n");
    Console.WriteLine(xmlFromPlainCode + "\n");
    Console.WriteLine("------ # Loaded XML Document # ------\n");
    Console.WriteLine(loadedDocument + "\n");

    PerformLinqQueryOnXml(xmlDocPath);
    SerializeToXml();
}

Let's start the application and check the output:

### Serialized Course data from obj ###

<?xml version="1.0" encoding="utf-16"?>
<Courses xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Academy>Coding with Christian Schou</Academy>
  <Course Id="1">
    <Title>How to get started with MailKit</Title>
    <Duration>4 hours and 42 minutes</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
  <Course Id="2">
    <Title>Dapper with repository in ASP.NET</Title>
    <Duration>4 hours and 30 minutes</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="EUR">Free</Price>
  </Course>
  <Course Id="3">
    <Title>How to create a WEB API</Title>
    <Duration>4 hours and 38 minutes</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">19.95</Price>
  </Course>
</Courses>

Great! The output looks exactly as we wanted! We have now created XML content from an object in C# that looks like exactly the one we generated using plain code. What if it were the other way around (XML to object)?

Build objects from XML (Deserialize XML)

Often we also have to work with XML in our application. This could be when starting an application and we would like to load some settings or we would like to insert some data into a database from an XML document.

We already have the models in place from earlier. This means that we can skip to the fun part, where we deserialize XML to objects in our application. Below is a new static method I have added at the very bottom of my program.cs class.

static void DeserializeXmlToObject()
{
    string serializedXml = SerializeToXml();

    Console.WriteLine("### Serialized Course data from obj ###\n");
    Console.WriteLine();
    Console.WriteLine(serializedXml);

    Console.WriteLine();
    Console.WriteLine("### Deserialize XML to Object ###");
    Console.WriteLine();

    XmlSerializer serializer = new XmlSerializer(typeof(Courses));

    using (StringReader reader = new StringReader(serializedXml))
    {
        var test = (Courses)serializer.Deserialize(reader);

        foreach (var course in test.CourseList)
        {
            Console.WriteLine($"Course No {course.Id}. with title {course.Title} costs {course.Price.Text} {course.Price.Currency}");
        }
    }
}

What is happening here?

We start off by calling our previous method that generated the XML and storing the result in a string. Easy peasy… Now for the final part. First, we initialize a new instance of the XmlSerializer with the type of Courses (model). Then we use a StringReader to read the serialized XML (it’s a string).

Then we create a new variable where we store the result of our deserialized XML using the String Reader. Finally, we run a foreach loop where we write out a new line in the console with data from the object we got from deserializing the XML.

Let’s spin up the application and see the result:

### Deserialize XML to Object ###

Course No 1. with title How to get started with MailKit costs Free DKK
Course No 2. with title Dapper with repository in ASP.NET costs Free EUR
Course No 3. with title How to create a WEB API costs 19.95 USD

The result is exactly as we expected. Now our XML document got deserialized and we are able to make operations on the data as we now got it stored in objects.

List of XML Libraries, frameworks, and tools for .NET

To make it easier for you to work with XML, I have added a short list below of some tools/frameworks you can take advantage of when working with XML in C#.

XPath, XQuery, and XSLT

  • System.XML – Provides standards-based support for processing XML.
  • XmlPrime – XmlPrime provides complete, fast and up-to-date implementations of XSLT 2.0, XQuery 3.1 and XPath 3.1 for the .NET Framework.
  • Saxon – XSLT and XQuery Processor. NuGet.

Validators

  • System.XML – Provides standards-based support for processing XML.
  • XMLUnit – Tools to verify the XML you emit is the one you want to create
  • Saxon – Saxon can be used as a free-standing schema processor.

Parsers

  • System.XML – Provides standards-based support for processing XML.
  • Mvp.XML – Supplements .NET framework XML processing functionality.
  • Apache Xerces – Included in Saxon, cross-compiled from Java.

Summary

I hope you learned something new or simply just got your XML issue solved by having a look at my article. This article was a very basic introduction to XML in C#. You are now ready to move on and get even better at working with XML in C#.

You now have the basic knowledge of how .NET provides a simple way to work with XML and how easy it is to convert objects to XML and XML to objects in C# fast without having to write tons of code. You are also capable of reading XML using LINQ at XElement.

The code is available on my GitHub if you would like to have a closer look at how I implemented the different classes and logic. Please let me know if you have any issues, suggestions, or questions in the comments below. Happy coding!

References

GitHub - maxtoroq/dotnet-xml: A list of XML libraries, frameworks and tools for .NET
A list of XML libraries, frameworks and tools for .NET - GitHub - maxtoroq/dotnet-xml: A list of XML libraries, frameworks and tools for .NET