Deep C# - XML in C#
Written by Mike James   
Thursday, 11 February 2021
Article Index
Deep C# - XML in C#
XML to XElement
Value

Converting XML To XElements

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 = @"
 <Name>
  <First />
  <Second />
 </Name>
 <Address />
</Record>";
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.

Content

Now you can see how to build an XElement tree but what about content?

A tree of XML tags isn’t usually the whole story. The main data payload in XML is suppose to be anything you put between opening and closing tags.

In the XElement tree any text between tags is stored as an XText node in the node collection i.e. it is just another type of child node.

As such you can add XText nodes using all of the methods described earlier – if you try to add a string object as a child then the methods simply convert it to an XText object and add it to the collection of nodes.

For example:

XElement root = new
XElement("Record","Address Record",
   new XElement("Name",
    new XElement("First","Mike"),
    new XElement("Second")),
   new XElement("Address"));

This adds “Address Record” and “Mike” as text between the specified tags. It is also worth knowing that if an XElement object has only a single XText child then this is also its string Value property.

Attributes

Text between the tags isn’t the only sort of data carried by XML.

You can also specify any number of name value pairs within the tags themselves as attributes.

Attributes are supposed to be used as “metadata”, i.e. they describe the nature of the data between the tags - formatting, time zone, context etc - and within the XElement tree they are stored as XAttribute objects within the Attributes collection.

The reason for this is that if you enumerate the tree you will list each of the tags and text between tags but not the attributes. Once you have found a tag, i.e. an XElement object, you can enumerate its attributes.

Viewed in this way it should be clear that the main distinction between attributes and other nodes is that attributes are not part of the tree structure being simply stored at each node of the tree.

The rule that you have to keep in mind is that if you add an XAttribute object to an XElement object then it will automatically be added to the Attributes collection.

For example:

XAttribute Att1=new XAttribute("Epoc",2000);
root.Add(Att1);

adds an attribute Epoc= “2000” to the Attributes collection. The XML generated reads:

<Record Epoc="2000"> …<Record>

You can achieve the same result using the function method of constructing an XML tree:

XElement root = new XElement("Record",
    new XAttribute("Epoc", 2000),
    new XElement("Name",
     new XElement("First","Mike"),
     new XElement("Second")),
    new XElement("Address"));

The Constructor Rules!

What the constructor or the Add method does with an object you supply to it depends on the object’s type.

The rules are:

  • If it’s null, nothing happens.
  • If it’s descended from XNode then it is added to the Nodes collection.
  • If it’s an XAttribute then it is added to the Attributes collection
  • If it’s a string then it is converted to XText and added to Nodes.

Less obvious behaviour is that if you supply an object that implements IEnumerable then it is enumerated and the resulting objects are treated as above and if an object is anything that can’t be handled by the above rules it’s converted to a String and then to an XText object and added to Nodes.

The IEnumerable behaviour is very handy because it means you can add a collection of objects in one step.

csharp

Manipulating the tree

Constructing a tree is usually just the beginning of the problem. You usually want to process, i.e. examine and change the tree as a result. As an XElement tree is dynamic this is fairly easy.

You can of course use Add to add additional elements of any kind and there are also two remove methods – RemoveNode and RemoveAttribute.  These simply remove the object that they belong to from the parents collection.

For example:

root.Add(child4);
child4.Remove();

This first adds child4 to root’s node collection and then removes it.

A particularly useful method is SetElementValue as this will modify an elements value and create a new object if it doesn’t already exist.

For example, the instruction:

root.SetElementValue("Tel","123");

will set an existing XElement child of root with XName “Tel” to a value of “123” or if such a XElement doesn’t exist it will first create a new instance.

There is some apparently odd behaviour here in that the value “123” is applied between a new pair of tags <Tel>123</Tel> but it is also appended to root’s Value property as if it was new text located between the <root></root>.

The reason for this is that the Value property is the concatenation of all the XText objects contained within its opening and closing tags. This makes the Value property often less than helpful.

Notice that if you add some additional text in the form of a string then it is simply added to any existing XText object as a concatenation. If you first explicitly create XText objects and add these then you get new child objects – which seems reasonable behaviour.

The SetAttributeValue method works in much the same way but on the Attribute collection.

For example:

root.SetAttributeValue("Epoc", "2008");

updates or adds an Epoc attribute.  As an attribute generally has only one value, its Value property is much more useful.

Another useful pair of methods are AddBeforeSelf and AddAfterSelf which, as their names suggest, allow the adding of elements above and below the current element in the tree.

There are lots of other methods that modify the tree structure but they are all fairly obvious and contain no surprises – check the documentation for details.



Last Updated ( Thursday, 11 February 2021 )