Until recently, I terribly did not like working with XML files, I tried to avoid it wherever possible, simply replacing them with standard application configuration files. But where it was necessary to use data exchange - it was impossible to leave XML. We had to create a large amount of code in order to convert or read a small amount of information. Yes, such is the XML Document Object Model (DOM) API.
XML DOM API Example
You need to get this message:
< Groups >
< Group Id ="523063B0-47C0-4ABE-8D38-4A449137A00B" DepartmentId ="D939743F-BFF7-41E4-9A1B-1193EEFF0486" >
< Name > 555A </ Name >
< Course > 5 </ Course >
</ Group >
</ Groups >
To do this, you need to write a fairly simple but voluminous code:
private sealed class Nodes
{
public const string Root = "Groups" ;
// Attributes.
public const string Group = "Group" ;
public const string Id = "Id" ;
public const string DepartmentId = "DepartmentId" ;
// Elements.
public const string Name = "Name" ;
public const string Course = "Course" ;
}
// Create XML document.
XmlDocument document = new XmlDocument ();
// Create root element.
XmlElement rootElement = document.CreateElement( Nodes .Root);
// Create Group element.
XmlElement groupElement = document.CreateElement( Nodes .Group);
// Create attributes.
XmlAttribute idAttribute = document.CreateAttribute( Nodes .Id);
idAttribute.InnerText = "523063B0-47C0-4ABE-8D38-4A449137A00B" ;
groupElement.Attributes.Append(idAttribute);
XmlAttribute departmentIdAttribute = document.CreateAttribute( Nodes .DepartmentId);
departmentIdAttribute.InnerText = "D939743F-BFF7-41E4-9A1B-1193EEFF0486" ;
groupElement.Attributes.Append(departmentIdAttribute);
// Create elements.
XmlElement nameElement = document.CreateElement( Nodes .Name);
nameElement.InnerText = "555A" ;
groupElement.AppendChild(nameElement);
XmlElement courseElement = document.CreateElement( Nodes .Course);
courseElement.InnerText = "5" ;
groupElement.AppendChild(courseElement);
rootElement.AppendChild(groupElement);
document.AppendChild(rootElement);
Agree with me that writing, disassembling and accompanying such code is not very pleasant.
')
With this code, it is impossible to get an idea of ββthe resulting XML structure. With each element or attribute, you must always perform three steps: create, set the InnerText property and add to an already existing element or document. Also, without creating an XmlDocument, it is impossible to simply create an element, and this is necessary quite often.
Fortunately, Microsoft gave us not only the ability to perform integrated LINQ to XML queries, but also reworked the XML DOM API.
This is what I want to tell more today. For this you need to connect the following namespaces:
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
As I said, one of the drawbacks of the standard DOM model was the hard-to-read structure of the resulting XML file. The LINQ to XML API solves this problem by offering a new technique called functional design. Functional design allows you to construct XML objects and initialize their values βββ at the same time, in a single statement, at the expense of many overloaded constructors.
Let's see how the construction of an XML file already known to us using the LINQ to XML API will look like:
XElement document = new XElement ( Nodes .Root,
new XElement ( Nodes .Group,
new XAttribute ( Nodes .Id, "523063B0-47C0-4ABE-8D38-4A449137A00B" ),
new XAttribute ( Nodes .DepartmentId, "D939743F-BFF7-41E4-9A1B-1193EEFF0486" ),
new XElement ( Nodes .Name, "555A" ),
new XElement ( Nodes .Course, 5)));
Well, how? Which code is easier for you to read? The answer is obvious.
Object model

The
XObject ,
XNode, and
XContainer classes are abstract, so we cannot create them.
The
XAttribute class is not inherited from
XNode , i.e. is not a node; it is a simple element of the collection that represents a key-value pair.
The
XDocument and
XElement classes are the only ones that can contain nodes inherited from
XNode .
Xdocument
In LINQ to XML API, it is not at all necessary to create an
XDocument in order to create an XML tree or its fragment.
XDocument document = new XDocument ();
Console .WriteLine(document.ToString());
We get an empty result.
XDocument by itself has nothing useful, only the ability to add an ad to the document (
XDeclaration ), type creation (
XDocumentType ) or processing instruction (
XProcessingInstruction ).
It has static methods for reading the contents of documents, with various options for overloads:
public static XDocument Load( Stream stream);
public static XDocument Load( string uri);
public static XDocument Load( TextReader textReader);
public static XDocument Load( XmlReader reader);
public static XDocument Load( Stream stream, LoadOptions options);
public static XDocument Load( string uri, LoadOptions options);
public static XDocument Load( TextReader textReader, LoadOptions options);
public static XDocument Load( XmlReader reader, LoadOptions options);
And also to save the document:
public void Save( Stream stream);
public void Save( string fileName);
public void Save( TextWriter textWriter);
public void Save( XmlWriter writer);
public void Save( Stream stream, SaveOptions options);
public void Save( string fileName, SaveOptions options);
public void Save( TextWriter textWriter, SaveOptions options);
The element (
XElement ) has the same methods.
I use
XDocument only if I need to set an advertisement for a document that contains the version number and encoding.
Xdeclaration
XDeclaration objects, as you may have guessed, contain declarations and are added to the document, although the compiler allows adding declarations to the element (
XElement ), but this will not give any visible result.
XDocument document = new XDocument (
new XDeclaration ( "1.0" , "UTF-8" , "yes" ));
Console .WriteLine(document.ToString());
This code also does not display any lines, although if you look at the debugger, the ad is still added:

The declaration will be visible if you use the
Save () method of the
XDocument class.
Xelement
The most commonly used API object.
It has many designers, consider two of them:
public XElement ( XName name, object content);
public XElement ( XName name, params object [] content);
The first constructor is the simplest case when an element has no child elements and we specify only its value, the second constructor specifies child elements such as elements, attributes, processing instructions, comments (
XComment ), etc.
Create the simplest element:
XElement element = new XElement ( "Element" , 777);
Console .WriteLine(element.ToString());
Console .WriteLine(( int )element);
Result:
< Element > 777 </ Element >
777
As you can see, access to the value has become even easier due to the overridden explicit casting of elements; it is enough to cast the element to its original type in order to see its value.
XElement overrides the explicit cast for all simplest types. Now even the
Value property is not necessary to access.
You ask, the constructor requires
XName , and I pass it a string? And I will answer you: the string is implicitly
cast to an
XName object. In essence,
XName is a string, only with the possibility of defining a namespace (
XNamespace ).
I will give a more detailed example of creating XML from objects:
public sealed class Teacher
{
public Guid Id;
public string FirstName;
public string LastName;
}
IEnumerable < Teacher > teachers = new []
{
new Teacher () { Id = Guid .NewGuid(), FirstName = "" , LastName = "" },
new Teacher () { Id = Guid .NewGuid(), FirstName = "" , LastName = "" }
};
XElement elements = new XElement ( "Teachers" ,
teachers.Select(t => new XElement ( "Teacher" ,
new XAttribute ( "Id" , t.Id),
new XElement ( "FirstName" , t.FirstName),
new XElement ( "LastName" , t.LastName))));
Console .WriteLine(elements.ToString());
As a result, we have:
< Teachers >
< Teacher Id ="80321d66-ee4b-4b55-ace8-3892b682d483" >
< FirstName > </ FirstName >
< LastName > </ LastName >
</ Teacher >
< Teacher Id ="33f58b19-1bbb-468f-acee-961edb63ce0b" >
< FirstName > </ FirstName >
< LastName > </ LastName >
</ Teacher >
</ Teachers >
XAttribute
As I said earlier, is a key-value pair for the collection of element attributes. Creating and adding attributes to an element is quite a simple task:
XAttribute attribute = new XAttribute ( "Id" , Guid .NewGuid());
XElement element = new XElement ( "Teachers" );
element.Add(attribute);
Console .WriteLine(element.ToString());
Or:
XElement element = new XElement ( "Teachers" ,
new XAttribute ( "Id" , Guid .NewGuid()));
Console .WriteLine(element.ToString());
The result is the same:
< Teachers Id ="713c6cbf-f698-42fd-b5fc-74415b93d824" />
Xcomment
Creating and adding comments also does not cause any difficulties:
XElement teacherElement = new XElement ( "Teacher" ,
new XComment ( "Teacher element" ));
Console .WriteLine(teacherElement.ToString());
Result:
< Teacher >
<!--Teacher element-->
</ Teacher >
Conclusion
At this stage I would like to finish. Yes, I did not consider using examples of processing instructions, creating document types and other model classes, but this knowledge will be enough to create both simple and complex in structure XML documents.
In the next article, I plan to consider a walk through the contents of an XML document.