Page 1 of 3
.NET has some really easy-to-use facilities for creating and editing XML. Many of these facilities were introduced to make Linq to XML work better but you can make use of them in more general situations.
There always was good XML support in .NET but Linq adds a set of classes that makes it easier to work with XML, particularly if you’re not an XML specialist.
There are a number of standard protocols and ways of working with XML – Xpath, SAX, DOM and so on. All of them are good but they all focus on some specific particular aspect of XML and a particular way of getting the job done. Linq’s version of XML goes “back to basics”.
It is important to realise that much of what we are about to investigate can be used without the need to make use of Linq - it all just happens to be a very easy way to work with XML in general.
Even if you aren’t interested in working with XML looking at how Linq handles a more complicated data structure, a tree in this case, is instructive and has a lot to teach you about the way Linq is designed, how it works and how you might extend it to other data structures. In this article we look at how to construct the tree structure that XML is all about and in a future article we look at how to use such structures with Linq.
The core of XML is the tag as in
- an opening tag, e.g. <Record>
- a closing tag, e.g. </Record>
The rules for XML are simple – tags occur, almost always, in matched pairs and you can nest tags as if they were brackets. The only exception to the matched pairs rule is a tag that is its own closing tag – as in <Record/> which opens and closes the tag in one go.
It’s not difficult to see that you can use tags to build a general tree structure and all you need to represent it in a program is a class that has a collection of itself as a property.
This is exactly how the xNode class, and the more useful xElement descended from it via xContainer, operate.
The important point is that xElement has a Nodes collection which can be used to store an element’s child elements.
A simple example will make this clear.
First we need a root node:
XElement root = new XElement("Record");
The string “Record” is automatically converted to an XName object and this is used to set the Name property of the new XElement. An XName is used instead of a simple string because XML names have some additional behaviour because of namespaces – more later.
Now have a root for our tree let’s create a leaf node
XElement child1 = new XElement("Name");
and hang it off the tree….
If you place a textbox on a form you can see the XML that the tree represents using:
textBox1.Text = root.ToString();
What you will see is:
You can carry on in the same way to build up a tree of any complexity you like.
XElement root=new XElement("Record");
XElement child1=new XElement("Name");
XElement child2=new XElement("First");
XElement child3=new XElement("Second");
XElement child4=new XElement("Address");
creates the following XML:
The idea of nesting XElements within XElements is fairly obvious but there are neater ways of achieving the same result.
For example, you can combine the two Add methods into a single call:
The reason this works is due to an overload of Add not mentioned in the documentation:
public void Add(params object content);
You can, of course construct a list of child objects to insert into multiple XElements if you want to.
Another style of XML tree construction is based on the use of the XElement constructor.
One overloaded version allows you to specify the XElements content. So to create an XElement with two children you would use:
XElement root = new XElement("Record",
You can continue this nested construction to any level you need to.
For example, the following creates the same XML tree we had earlier:
XElement root = new XElement("Record",
This is generally referred to as “functional construction” and if you format it correctly then it looks like the tree it is constructing and it has the advantage that you can pass it directly to any method that cares to make use of it. Of course in this style of construction you don’t get variables to keep track of each node but in most cases you don’t need them.
There are two additional very easy ways of converting XML into an XElement tree – the static Load and Parse methods.
Load will take a file specification as a URI or as a TextReader or XmlReader and parse the text stream into an XElement tree.
The Parse method does the same but by accepting a string of XML tags.
For example, to construct the same XML tree given earlier:
string XML = @"
XElement root= XElement.Parse(XML) ;
If the XML you try to load or parse is syntactically incorrect then you will have to handle the resulting exception.
If you want to go the other way then there is a Save method and you can specify options on the Save and the ToString methods that control some aspects of formatting.