Introduction to XML Elements
Introduction to XML Elements
The Child Nodes of a Node
Introduction
As mentioned already, one node can be nested inside of another. A nested node is called a child of the nesting node. This also implies that a node can have as many children as necessary, making them child nodes of the parent node. Once again, consider our Videos.xml example:
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> </video> <video> <title>Her Alibi</title> <director>Bruce Beresford</director> <length>94 Mins</length> <format>DVD</format> <rating>PG-13</rating> </video> <video> <title>Chalte Chalte</title> <director>Aziz Mirza</director> <length>145 Mins</length> <format>DVD</format> <rating>N/R</rating> </video> </videos>
The title and the director nodes are children of the video node. The video node is the parent of both the title and the director nodes.
A Collection of XML Nodes
As you may know already, an XML document usually contains many nodes. To consider a collection of nodes, the .NET Framework provides a collection class named XmlNodeList. It starts as follows:
public abstract class XmlNodeList : IEnumerable, IDisposable
Linking the Nodes
To manage the relationships among the nodes of an XML document, the .NET Framework provides a class named XmlLinkedNode:
public abstract class XmlLinkedNode : XmlNode
As a result, many classes derive from XmlLinkedNode. That's the case for the XmlElement class to which we were introduced in the previous lesson:
public class XmlElement : XmlLinkedNode
A Collection of Child Nodes
To support the child nodes of a particular node, the XmlNode class is equipped with a property named ChildNodes. That property is of type XmlNodeList. The property is declared as follows:
public virtual XmlNodeList ChildNodes { get; }
When this property is used, it produces an XmlNodeList list, which is a collection of all nodes that share the same parent. Each item in the collection is of type XmlNode. To give you the number of nodes on an XmlNodeList collection, the class is equipped with a property named Count. Here is an example of using it:
using System; using System.IO; using System.Xml; public class Exercise { public static int Main(string[] args) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; FileInfo fiVideos = new FileInfo(strVideosFile); Console.Title = "Videos Collection"; Console.WriteLine("Videos Collection"); Console.WriteLine("-----------------------------------"); if (fiVideos.Exists == true) { xdVideos.Load(fiVideos.FullName); XmlElement xeVideo = xdVideos.DocumentElement; XmlNodeList xnlVideos = xeVideo.ChildNodes; Console.WriteLine("The root element contains {0} nodes.", xnlVideos.Count); } else Console.WriteLine("The file could not be located."); Console.WriteLine("==================================="); return 10; } }
This would produce:
Videos Collection ----------------------------------- The root element contains 3 nodes. =================================== Press any key to continue . . .
You can also use the Count property in a loop (while, do...while, or for) to visit the members of the collection.
Accessing a Node in a Collection
The children of a node, that is, the members of a ChildNodes property, or the members of an XmlNodeList collection, can be located each by an index. The first node has an index of 0, the second has an index of 1, and so on. To give you access to a node of the collection, the XmlNodeList class is equipped with an indexed property and a method named Item. Both produce the same result. For example, if a node has three children, to access the third, you can apply an index of 2 to its indexed property. Here is an example:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnVideosCollection_Click(object sender, EventArgs e) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; FileInfo fiVideos = new FileInfo(strVideosFile); if (fiVideos.Exists == true) { xdVideos.Load(strVideosFile); XmlElement xeVideo = xdVideos.DocumentElement; XmlNodeList xnlVideos = xeVideo.ChildNodes; MessageBox.Show(string.Format("Inner Text: {0}", xnlVideos[2].InnerText), "Videos Collection"); } else MessageBox.Show("The file could not be located.", "Videos Collection"); } } }
You can also use the Item() method to get the same result. Using a loop (while, do...while, or for), you can access each node and display the values of its children as follows:
using System; using System.IO; using System.Xml; public class Exercise { public static int Main(string[] args) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; Console.Title = "Videos Collection"; Console.WriteLine("Videos Collection"); Console.WriteLine("-----------------------------------"); if(File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); XmlElement xeVideo = xdVideos.DocumentElement; XmlNodeList xnlVideos = xeVideo.ChildNodes; for (int i = 0; i < xnlVideos.Count; i++) Console.WriteLine("Inner Text: {0}", xnlVideos[i].InnerText); } else Console.WriteLine("The file could not be located."); Console.WriteLine("==================================="); return 10; } }
This would produce:
Videos Collection ----------------------------------- Inner Text: The Distinguished GentlemanJonathan Lynn112 MinutesDVDR Inner Text: Her AlibiBruce Beresford94 MinsDVDPG-13 Inner Text: Chalte ChalteAziz Mirza145 MinsDVDN/R =================================== Press any key to continue . . .
Instead of using the indexed property, the XmlNodeList class implements the IEnumerable interface. This allows you to use a foreach loop to visit each node of the collection. Here is an example:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnVideosCollection_Click(object sender, EventArgs e) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; FileInfo fiVideos = new FileInfo(strVideosFile); if (fiVideos.Exists == true) { xdVideos.Load(strVideosFile); XmlElement xeVideo = xdVideos.DocumentElement; XmlNodeList xnlVideos = xeVideo.ChildNodes; string strMessage = string.Empty; foreach (XmlNode node in xnlVideos) strMessage += node.InnerText + Environment.NewLine; MessageBox.Show(strMessage, "Videos Collection"); } else MessageBox.Show("The file could not be located.", "Videos Collection"); } } }
This would produce:
To better manage and manipulate the nodes of a collection of nodes, you must be able to access the desired node. The XmlNode class combined with the XmlNodeList class provide various means of getting to a node and taking the appropriate actions.
The Parent of a Node
Not all nodes have children, obviously. For example, the title node of our Videos.xml file doesn't have children. To let you find out whether a node has children, the XmlNode class is equipped with a Boolean property named HasChildNodes
public virtual bool HasChildNodes { get; }
If a node is a child, to get its parent, you can access a property named ParentNode.
Fundamentals of Element Creation
Introduction
As seen so far, to create an XML element, you can directly type the XML code in a document. When the file is saved, it is ready to be processed. In some applications, you will want the user to provide you with the necessary value(s) to create an element. Fortunately, the XmlDocument, the XmlNode, and the XmlElement classes provide all the necessary properties and methods to perform the routine operations of an XML file, an element, or a node. The primary operation consists of creating a new element or a node.
Before performing an operation, you will usually need to decide in what section of the file you want the action to be applied. As it happens, you have the root node, a particular node inside the document, parent of a node, the sibling of a node, etc. To get to a node, you will usually first get a reference to its XmlElement. To do this, you can declare an XmlElement variable and initialize it with that reference.
Appending an Element
To let you add an element to an XML document, the XmlNode class, which is the ancestor of all XML nodes of the .NET Framework, provides a method named AppendChild. Its syntax is:
public virtual XmlNode AppendChild(XmlNode newChild);
Calling this method an XmlElement object.
Adding a Value to the Root Node
Consider an XML file named Studies.xml that starts as follows:
<?xml version="1.0" encoding="utf-8" ?> <studies></studies>
To let you add something, such as a value, to the root node the XmlDocument class provides a method named CreateTextNode. This method returns an XmlText value. The syntax of this method is:
public virtual XmlText CreateTextNode(string text);
This method takes as argument the string that would constitute the value of the element. Before calling it, you should have used the XmlNode.AppendChild() method to create a node. Here is an example:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace Studies { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnStudies_Click(object sender, EventArgs e) { XmlDocument xdStudies = new XmlDocument(); string strXMLFile = @"C:\exercises\Studies.xml"; xdStudies.Load(strXMLFile); XmlElement xeRoot = xdStudies.DocumentElement; XmlText xtNursing = xdStudies.CreateTextNode("Nursing Studies - Curriculum"); // Add the child node to the root element xeRoot.AppendChild(xtNursing); xdStudies.Save(strXMLFile); } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<studies>Nursing Studies - Curriculum</studies>
Adding an Empty Element to the Root
Consider an XML file named Videos.xml whose content is:
<?xml version="1.0" encoding="utf-8"?> <videos />
To assist you with programmatically creating a new element, the XmlDocument class is equipped with a method named CreateElement. It is overloaded with three versions. One of the versions uses the following syntax:
public XmlElement CreateElement(string name);
To create a new element, call this method and pass the name of the new element to it. For example, imagine you want to add a new Title element to the above document. You would start with code as follows:
string strVideosFile = Server.MapPath("Videos.xml"); System.Xml.XmlDocument xdVideos = new System.Xml.XmlDocument(); if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); System.Xml.XmlElement xeNewVideo = xdVideos.CreateElement("Title"); }
After calling the CreateElement method, call the XmlDocument.AppendChild() method to add the new element to the root node. Here is an example:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnVideosCollection_Click(object sender, EventArgs e) { string strVideosFile = @"C:\Videos Collection\Videos.xml"; XmlDocument xdVideos = new XmlDocument(); if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); XmlElement xeRoot = xdVideos.DocumentElement; XmlElement xeNewVideo = xdVideos.CreateElement("title"); xeRoot.AppendChild(xeNewVideo); } else { // Create the default XML structure xdVideos.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<videos></videos>"); } xdVideos.Save(strVideosFile); } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<videos>
<title />
</videos>
Adding a Full Element to the Root
Consider a starting XML file named Studies.xml whose content is:
<?xml version="1.0" encoding="utf-8"?> <studies> </studies>
We know (from the previous lesson) that the XmlNode class is equipped with the InnerXml property that holds a whole XML element. To add a new element to the root node, create the whole markup of the node. If necessary, include its child(ren) with its (their) markup(s) as a string and assign that string to an XmlNode.InnerXml string. Here is an example of using this property:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace Studies { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnStudies_Click(object sender, EventArgs e) { XmlDocument xdStudies = new XmlDocument(); string strStudies = @"C:\exercises\Studies.xml"; if (File.Exists(strStudies)) { using (FileStream fsStudies = new FileStream(strStudies, FileMode.Open, FileAccess.Read, FileShare.Read)) xdStudies.Load(fsStudies); XmlElement xeStudy = xdStudies.CreateElement("degrees"); string strStudio = "<undergraduate>Bachelor of Science in Nursing (BSN)</undergraduate>" + "<graduate>Master of Science in Nursing (MSN)</graduate>" + "<doctoral>Doctor of Nursing Practice (DNP)</doctoral>"; xeVideo.InnerXml = strStudio; xdStudies.DocumentElement.AppendChild(xeStudy); using (FileStream fsStudies = new FileStream(strStudies, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write)) xdStudies.Save(fsStudies); } } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<studies>
<degrees>
<undergraduate>Bachelor of Science in Nursing (BSN)</undergraduate>
<graduate>Master of Science in Nursing (MSN)</graduate>
<doctoral>Doctor of Nursing Practice (DNP)</doctoral>
</degrees>
</studies>
Once again, consider a starting XML file named Studies.xml:
<?xml version="1.0" encoding="utf-8"?> <studies> </studies>
Adding an Element with Sub-Elements
You can create an element that has child elements that themselves have child elements. Here is an example:
using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;
namespace VideosCollection
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnStudies_Click(object sender, EventArgs e)
{
XmlDocument xdStudies = new XmlDocument();
FileInfo fiStudies = new FileInfo(@"C:\exercises\Studies.xml");
if (fiStudies.Exists == true)
{
using (FileStream fsStudies = new FileStream(fiStudies.FullName, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
xdStudies.Load(fsStudies);
}
XmlElement xeStudy = xdStudies.CreateElement("freshman");
string strNursingProgram = "<fall-term><course>Human Anatomy & Physiology I</course>" +
"<course>Introduction to Practice-Based Research I</course>" +
"<course>English Composition for Health Professions</course>" +
"<course>Infant Psychology</course>" +
"<course>Introduction to Expressive Sociology</course></fall-term>" +
"<spring><course>Introduction to Statistics in Health Care</course>" +
"<course>Human Anatomy & Physiology II</course>" +
"<course>Microbiology I</course></spring>";
xeStudy.InnerXml = strNursingProgram;
xdStudies.DocumentElement.AppendChild(xeStudy);
using (FileStream fsStudies = new FileStream(fiStudies.FullName, FileMode.OpenOrCreate,
FileAccess.Write, FileShare.Write))
{
xdStudies.Save(fsStudies);
}
}
}
}
}
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<studies>
<freshman>
<fall-term>
<course>Human Anatomy & Physiology I</course>
<course>Introduction to Practice-Based Research I</course>
<course>English Composition for Health Professions</course>
<course>Infant Psychology</course>
<course>Introduction to Expressive Sociology</course>
</fall-term>
<spring>
<course>Introduction to Statistics in Health Care</course>
<course>Human Anatomy & Physiology II</course>
<course>Microbiology I</course>
</spring>
</freshman>
</studies>
Suppose that a document already contains one or more elements. Here is example of a file named videos.xml:
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> </video> <video> <title>Her Alibi</title> <director>Bruce Beresford</director> <length>94 Minutes</length> <format>DVD</format> <rating>PG-13</rating> </video> </videos>
To add a new element as a child of the root, "build" one or all child elements, then assign the element to the XmlNode.InnerXml property. Here is an example:
using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;
namespace VideosCollection
{
public partial class Form1 : Form
{
public Form1() => InitializeComponent();
private void btnVideosCollection_Click(object sender, EventArgs e)
{
XmlDocument xdVideos = new XmlDocument();
string strVideosFile = @"C:\Videos Collection\Videos.xml";
if (File.Exists(strVideosFile))
{
xdVideos.Load(strVideosFile);
XmlElement xeVideo = xdVideos.CreateElement("video");
string strNewvideo = "<title>Other People's Money</title>" +
"<director>Alan Brunstein</director>" +
"<length>114 Minutes</length>" +
"<format>VHS</format>" +
"<rating>PG-13</rating>";
xeVideo.InnerXml = strNewvideo;
xdVideos.DocumentElement.AppendChild(xeVideo);
}
else
{
// Create the default XML structure
xdVideos.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<videos></videos>");
}
xdVideos.Save(strVideosFile);
}
}
}
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<videos>
<video>
<title>The Distinguished Gentleman</title>
<director>Jonathan Lynn</director>
<length>112 Minutes</length>
<format>DVD</format>
<rating>R</rating>
</video>
<video>
<title>Her Alibi</title>
<director>Bruce Beresford</director>
<length>94 Minutes</length>
<format>DVD</format>
<rating>PG-13</rating>
</video>
<video>
<title>Other People's Money</title>
<director>Alan Brunstein</director>
<length>114 Minutes</length>
<format>VHS</format>
<rating>PG-13</rating>
</video>
</videos>
The Last Child Node
Introduction
The child node that immediately precedes the end-tag of the parent node is called the last child. To give you access to the last child of a node, the XmlNode class is equipped with a property named LastChild. It is declared as follows:
public virtual XmlNode LastChild { get; }
Appending a Last Element
We saw that, to create a new element, the XmlDocument class provides the overloaded CreateElement() method. To add the new element to a file, you must specify its position in the tree. For example, you may want the new element to be positioned as the last node.
To support the positions of existing nodes, the XmlNode class, which is the ancestor of all XML nodes of the .NET Framework, provides various methods, including the AppendChild method that we saw already. It is used to add an element as the last child of its parent. Normally, when you add an element to the root node, the new element is added as the last. An alternative is to call the LastChild property of the root node. As a result, the following code:
using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;
namespace Studies
{
public partial class Form1 : Form
{
public Form1() => InitializeComponent();
private void btnVideosCollection_Click(object sender, EventArgs e)
{
XmlDocument xdStudies = new XmlDocument();
string strStudies = @"C:\exercises\Studies.xml";
FileInfo fiStudies = new FileInfo(strStudies);
if( fiStudies.Exists == true )
{
using (FileStream fsStudies = new FileStream(fiStudies.FullName, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
xdStudies.Load(fsStudies);
}
XmlElement xeStudy = xdStudies.CreateElement("sophomore");
string strNursingProgram = "<fall-term><course>Foundations of Pathology</course>" +
"<course>Computer Databases I</course>" +
"<course>Human Anatomy & Physiology III</course>" +
"<course>Infant Psychology II</course>" +
"<course>Pharmacology I</course></fall-term>" +
"<spring><course>Foundations of Clinical Nursing</course>" +
"<course>Desktop Applications</course>" +
"<course>Microbiology II</course></spring>";
xeStudy.InnerXml = strNursingProgram;
xdStudies.DocumentElement.AppendChild(xeStudy);
using (FileStream fsStudies = new FileStream(strStudies, FileMode.OpenOrCreate,
FileAccess.Write, FileShare.Write))
{
xdStudies.Save(fsStudies);
}
}
}
}
}
is the same as:
using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;
namespace VideosCollection
{
public partial class Form1 : Form
{
public Form1() => InitializeComponent();
private void btnVideosCollection_Click(object sender, EventArgs e)
{
XmlDocument xdStudies = new XmlDocument();
string strStudies = @"C:\exercises\Studies.xml";
FileInfo fiStudies = new FileInfo(strStudies);
if( fiStudies.Exists == true )
{
. . .
xeStudy.InnerXml = strNursingProgram;
xdStudies.DocumentElement.LastChild.AppendChild(xeStudy);
using (FileStream fsStudies = new FileStream(strStudies, FileMode.OpenOrCreate,
FileAccess.Write, FileShare.Write))
{
xdStudies.Save(fsStudies);
}
}
}
}
}
Adding an Element to the Last Child Node
Consider an XML file named Studies.xml that has the following content:
<?xml version="1.0" encoding="utf-8"?> <studies> <nursing> </nursing> <mechanical-engineering> <freshman> <fall> <course>Physics I</course> <course>General Chemistry</course> </fall> <spring> <course>Integral Calculus</course> <course>Computing for Engineers</course> </spring> </freshman> <sophomore></sophomore> </mechanical-engineering> </studies>
To a new element as a child of the last node of a document, you can access the LastChild property of the LastChild of the root node. Of course, make sure you Call the AppendChild() method of the root node. Here is an example:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace Studies { public partial class Form1 : Form { public Form1() => InitializeComponent(); private void btnStudies_Click(object sender, EventArgs e) { XmlDocument xdStudies = new XmlDocument(); string strStudies = @"C:\exercises\Studies.xml"; if (File.Exists(strStudies)) { using (FileStream fsStudies = new FileStream(strStudies, FileMode.Open, FileAccess.Read, FileShare.Read)) { xdStudies.Load(fsStudies); } XmlElement xeStudy = xdStudies.CreateElement("fall"); string strNursingProgram = "<course>Multivariable Calculus I</course>" + "<course>Differential Equations I</course>" + "<course>Computing Techniques</course>" + "<course>Dynamics of Rigid Bodies</course>"; xeStudy.InnerXml = strNursingProgram; xdStudies.DocumentElement.LastChild.LastChild.AppendChild(xeStudy); using (FileStream fsStudies = new FileStream(strStudies, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write)) { xdStudies.Save(fsStudies); } } } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<studies>
<nursing>
</nursing>
<mechanical-engineering>
<freshman>
<fall>
<course>Physics I</course>
<course>General Chemistry</course>
</fall>
<spring>
<course>Integral Calculus</course>
<course>Computing for Engineers</course>
</spring>
</freshman>
<sophomore>
<fall>
<course>Multivariable Calculus I</course>
<course>Differential Equations I</course>
<course>Computing Techniques</course>
<course>Dynamics of Rigid Bodies</course>
</fall>
</sophomore>
</mechanical-engineering>
</studies>
Consider the following XML file named "videos.xml":
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> </video> <video> <title>Basic Instinct</title> </video> </videos>
Notice that the root, videos, has a repetitive child named video. This video child has its own child named Title. Imagine that you want to add a new video node that has a child. To do this, first create an empty video node as a child of the root. We learned earlier how to do that:
using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;
namespace VideosCollection
{
public partial class Form1 : Form
{
public Form1() => InitializeComponent();
private void btnVideosCollection_Click(object sender, EventArgs e)
{
XmlDocument xdVideos = new XmlDocument();
string strVideosFile = @"C:\Videos Collection\Videos.xml";
if (File.Exists(strVideosFile))
{
xdVideos.Load(strVideosFile);
XmlElement xeRoot = xdVideos.DocumentElement;
XmlElement xeNewVideo = xdVideos.CreateElement("video");
xeRoot.AppendChild(xeNewVideo);
}
else
{
xdVideos.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<videos></videos>");
}
xdVideos.Save(strVideosFile);
}
}
}
After creating the new child of the root, initialize the grand child with the desired name (the name doesn't have to be one of the existing names) and a value (which is optional if you want the new node to have a value). Once the new node is ready, append it as the last child of the root. If this new node has a value, append its XmlText object as the LastChild of the LastChild of the root. Here is an example of how you would do this:
using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;
namespace VideosCollection
{
public partial class Form1 : Form
{
public Form1() => InitializeComponent();
private void btnVideosCollection_Click(object sender, EventArgs e)
{
XmlDocument xdVideos = new XmlDocument();
string strVideosFile = @"C:\Videos Collection\Videos.xml";
FileInfo fiVideos = new FileInfo(strVideosFile);
if(fiVideos.Exists == true )
{
xdVideos.Load(fiVideos.FullName);
XmlElement xeRoot = xdVideos.DocumentElement;
XmlElement xeNewVideo = xdVideos.CreateElement("video");
xeRoot.AppendChild(xeNewVideo);
xeRoot = xdVideos.DocumentElement;
xeNewVideo = xdVideos.CreateElement("title");
XmlText xtVideo = xdVideos.CreateTextNode("Her Alibi");
xeRoot.LastChild.AppendChild(xeNewVideo);
xeRoot.LastChild.LastChild.AppendChild(xtVideo);
}
else
{
xdVideos.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<videos></videos>");
}
xdVideos.Save(fiVideos.FullName);
}
}
}
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<videos>
<video>
<title>The Distinguished Gentleman</title>
</video>
<video>
<title>Basic Instinct</title>
</video>
<video>
<title>Her Alibi</title>
</video>
</videos>
Now consider the following file:
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> </video> <video> <title>Her Alibi</title> <director>Bruce Beresford</director> <length>94 Minutes</length> <format>DVD</format> <rating>PG-13</rating> </video> </videos>
The root, videos, has a child node named video. The video node has many child nodes. By now, we know how to add a child to the root. We also saw how to add a grand child with value to the root. To add many (grand) children to a node, first build the node, add it to the root, then continuously add the necessary nodes, one at a time, including its name and its optional value. This can be done as follows:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() => InitializeComponent(); private void btnVideosCollection_Click(object sender, EventArgs e) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); XmlElement xeRoot = xdVideos.DocumentElement; XmlElement xeNewVideo = xdVideos.CreateElement("video"); xeRoot.AppendChild(xeNewVideo); xeRoot = xdVideos.DocumentElement; xeNewVideo = xdVideos.CreateElement("title"); XmlText xtVideo = xdVideos.CreateTextNode("The Day After Tomorrow"); xeRoot.LastChild.AppendChild(xeNewVideo); xeRoot.LastChild.LastChild.AppendChild(xtVideo); xeNewVideo = xdVideos.CreateElement("director"); xtVideo = xdVideos.CreateTextNode("Roland Emmerich"); xeRoot.LastChild.AppendChild(xeNewVideo); xeRoot.LastChild.LastChild.AppendChild(xtVideo); xeNewVideo = xdVideos.CreateElement("length"); xtVideo = xdVideos.CreateTextNode("124 Minutes"); xeRoot.LastChild.AppendChild(xeNewVideo); xeRoot.LastChild.LastChild.AppendChild(xtVideo); xeNewVideo = xdVideos.CreateElement("format"); xtVideo = xdVideos.CreateTextNode("DVD"); xeRoot.LastChild.AppendChild(xeNewVideo); xeRoot.LastChild.LastChild.AppendChild(xtVideo); xeNewVideo = xdVideos.CreateElement("rating"); xtVideo = xdVideos.CreateTextNode("PG-13"); xeRoot.LastChild.AppendChild(xeNewVideo); xeRoot.LastChild.LastChild.AppendChild(xtVideo); } else { xdVideos.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<videos></videos>"); } xdVideos.Save(strVideosFile); } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<videos>
<video>
<title>The Distinguished Gentleman</title>
<director>Jonathan Lynn</director>
<length>112 Minutes</length>
<format>DVD</format>
<rating>R</rating>
</video>
<video>
<title>Her Alibi</title>
<director>Bruce Beresford</director>
<length>94 Minutes</length>
<format>DVD</format>
<rating>PG-13</rating>
</video>
<video>
<title>The Day After Tomorrow</title>
<director>Roland Emmerich</director>
<length>124 Minutes</length>
<format>DVD</format>
<rating>PG-13</rating>
</video>
</videos>
Using the same approach, you can add children to children of children, and so on.
This code creates an empty element. If you want to create an element that includes a value, create its text and add that text to the node. Here is an example:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() => InitializeComponent(); private void btnVideosCollection_Click(object sender, EventArgs e) { FileInfo fiVideos = null; XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; fiVideos = new FileInfo(strVideosFile); if( fiVideos.Exists == true ) { xdVideos.Load(fiVideos.FullName); // Create a list of nodes whose name is Title XmlNodeList xnlTitles = xdVideos.GetElementsByTagName("title"); // Now you can check each node of the list foreach (XmlNode node in xnlTitles) { // When you get to a node, look for the element's value // If you find an element whose value is Her Alibi if (node.InnerText == "The Distinguished Gentleman") { // Create an element named Category XmlElement xeNewVideo = xdVideos.CreateElement("category"); // Create the text of the new element XmlText txtCatetory = xdVideos.CreateTextNode("Comedy"); // Get a reference to the parent of the node we have found XmlNode elmParent = node.ParentNode; // Add the new element to the node we found elmParent.AppendChild(xeNewVideo); // Specify the text of the new node elmParent.LastChild.AppendChild(txtCatetory); // Save the file xdVideos.Save(fiVideos.FullName); } } } } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> <category>Comedy</category> </video> . . . </videos>
Using the same approach combined with what we learned about adding an item, you can add a new element that itself has child nodes. Here is an example:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() => InitializeComponent(); private void btnVideosCollection_Click(object sender, EventArgs e) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); // Get a reference to the root node XmlElement xeRoot = xdVideos.DocumentElement; // Create a list of nodes whose name is Title XmlNodeList xnlTitles = xdVideos.GetElementsByTagName("title"); // Now you can check each node of the list foreach (XmlNode node in xnlTitles) { // When you get to a node, look for the element's value // If you find an element whose value is The Day After Tomorrow if (node.InnerText == "The Day After Tomorrow") { // Create an element named Actors XmlElement xeNewVideo = xdVideos.CreateElement("actors"); // Get a reference to the parent of the node we have found XmlNode elmVideo = node.ParentNode; // Add the new element to the node we found elmVideo.AppendChild(xeNewVideo); // Create an element as a child of the new element // Specify its name as Actor xeNewVideo = xdVideos.CreateElement("actor"); // Create the text of the new element XmlText txtActor = xdVideos.CreateTextNode("Dennis Quaid"); // Add the new Actor element to the Actors node elmVideo.LastChild.AppendChild(xeNewVideo); // Specify the text of the new node elmVideo.LastChild.LastChild.AppendChild(txtActor); // In the same way, add the other Actor nodes xeNewVideo = xdVideos.CreateElement("actor"); txtActor = xdVideos.CreateTextNode("Jake Gyllenhaal"); elmVideo.LastChild.AppendChild(xeNewVideo); elmVideo.LastChild.LastChild.AppendChild(txtActor); xeNewVideo = xdVideos.CreateElement("actor"); txtActor = xdVideos.CreateTextNode("Emmy Rossum"); elmVideo.LastChild.AppendChild(xeNewVideo); elmVideo.LastChild.LastChild.AppendChild(txtActor); xeNewVideo = xdVideos.CreateElement("actor"); txtActor = xdVideos.CreateTextNode("Dash Mihok"); elmVideo.LastChild.AppendChild(xeNewVideo); elmVideo.LastChild.LastChild.AppendChild(txtActor); // Save the file xdVideos.Save(strVideosFile); } } } } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?> <videos> . . . <video> <title>The Day After Tomorrow</title> <director>Roland Emmerich</director> <length>124 Minutes</length> <format>DVD</format> <rating>PG-13</rating> <actors> <actor>Dennis Quaid</actor> <actor>Jake Gyllenhaal</actor> <actor>Emmy Rossum</actor> <actor>Dash Mihok</actor> </actors> </video> </videos>
You can also insert one or more elements as children of an existing node after locating that node. Here is an example:
XML File
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> <category>Comedy</category> </video> <video> <title>Her Alibi</title> <director>Bruce Beresford</director> <length>94 Mins</length> <format>DVD</format> <rating>PG-13</rating> <actors /> </video> </videos>
Code Fragment:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() => InitializeComponent(); private void btnVideosCollection_Click(object sender, EventArgs e) { string strVideosFile = @"C:\Videos Collection\Videos.xml"; XmlDocument xdVideos = new XmlDocument(); if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); // Get a reference to the root node XmlElement xeRoot = xdVideos.DocumentElement; // Create a list of nodes whose name is Title XmlNodeList xnlTitles = xdVideos.GetElementsByTagName("title"); // Now you can check each node of the list foreach (XmlNode node in xnlTitles) { // When you get to a node, look for the element's value // If you find an element whose value is Her Alibi if (node.InnerText == "Her Alibi") { // Get a reference to the video node that is // the parent of the video titled Her Alibi XmlNode xeVideo = node.ParentNode; // Create a list of the child nodes of the Her alibi video XmlNodeList xnlActors = xeVideo.ChildNodes; // Visit each item of the collection // looking for an element named Actors foreach (XmlNode nodActor in xnlActors) { // If you find an element named Actors if (nodActor.Name == "actors") { // Create a new element named Actor // Specify its name as Actor XmlElement xeNewVideo = xdVideos.CreateElement("actor"); // Create the text of the new element XmlText txtActor = xdVideos.CreateTextNode("Tom Selleck"); // Add the new Actor element to the Actors node xeVideo.LastChild.AppendChild(xeNewVideo); // Specify the text of the new node xeVideo.LastChild.LastChild.AppendChild(txtActor); // Add other Actor nodes xeNewVideo = xdVideos.CreateElement("actor"); txtActor = xdVideos.CreateTextNode("Paulina Porizkova"); xeVideo.LastChild.AppendChild(xeNewVideo); xeVideo.LastChild.LastChild.AppendChild(txtActor); xeNewVideo = xdVideos.CreateElement("actor"); txtActor = xdVideos.CreateTextNode("William Daniels"); xeVideo.LastChild.AppendChild(xeNewVideo); xeVideo.LastChild.LastChild.AppendChild(txtActor); // Save the file xdVideos.Save(strVideosFile); // Stop, in this example, we don't expect another Actors node break; } } } } } } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<videos>
<video>
<title>The Distinguished Gentleman</title>
<director>Jonathan Lynn</director>
<length>112 Minutes</length>
<format>DVD</format>
<rating>R</rating>
<category>Comedy</category>
</video>
<video>
<title>Her Alibi</title>
<director>Bruce Beresford</director>
<length>94 Minutes</length>
<format>DVD</format>
<rating>PG-13</rating>
<actors>
<actor>Tom Selleck</actor>
<actor>Paulina Porizkova</actor>
<actor>William Daniels</actor>
</actors>
</video>
</videos>
The First Child Node
Introduction
In a typical XML document, the first line is called the first child of the DOM. This would be:
<?xml version="1.0" encoding="utf-8"?>
After identifying or locating a node, the first node that immediately follows it is referred to as its first child.
Adding an Element as the First Child
Consider the following document saved in a file named Videos.xml:
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> </video> </videos>
To let you add a new element and position it as the first in an XML document, the XmlNode class is equipped with a method named PrependChild. Its syntax is:
public virtual XmlNode PrependChild(XmlNode newChild);
This method receives an argument as an XmlNode object and adds it on top of the XML document. Here is an example of calling it:
using System; using System.IO; using System.Xml; using System.Windows.Forms; namespace VideosCollection { public partial class Form1 : Form { public Form1() => InitializeComponent(); private void btnVideosCollection_Click(object sender, EventArgs e) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); XmlElement xeRoot = xdVideos.DocumentElement; XmlElement xeVideo = xdVideos.CreateElement("video"); // Specify the child nodes of the element xeVideo.InnerXml = "7243 4 92525 9 2" + "<title>Yanni - Tribute</title>" + "<director>George Veras</director>" + "<format>DVD</format>"; // Add the new element as the first node in the document xeRoot.PrependChild(xeVideo); xdVideos.Save(strVideosFile); } } } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<videos>
<Video>7243 4 92525 9 2
<title>Yanni - Tribute</title>
<director>George Veras</director>
<format>DVD</format>
</Video>
<video>
<title>The Distinguished Gentleman</title>
<director>Jonathan Lynn</director>
<length>112 Minutes</length>
<format>DVD</format>
<rating>R</rating>
</video>
</videos>
Accessing a First Child Node
Consider the following videos.xml XML file:
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> </video> <video> <title>Her Alibi</title> <director>Bruce Beresford</director> <length>94 Mins</length> <format>DVD</format> <rating>PG-13</rating> </video> <video> <title>Chalte Chalte</title> <director>Aziz Mirza</director> <length>145 Mins</length> <format>DVD</format> <rating>N/R</rating> </video> </videos>
In our videos.xml file, the first child of the first video node is the <title>The Distinguished Gentleman</title> element. The first child of the second <video> node is <title>Her Alibi</title>.
To let you get the first child of a node, the XmlNode class provides a property named FirstChild. It is declared as follows:
public virtual XmlNode FirstChild { get; }
In the following example, every time the parser gets to a video node, it displays the value of it first child:
using System; using System.IO; using System.Xml; public class Exercise { public static int Main(string[] args) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); XmlElement xeVideo = xdVideos.DocumentElement; XmlNodeList xnlVideos = xeVideo.ChildNodes; foreach (XmlNode node in xnlVideos) Console.WriteLine("First Child Inner Text: {0}", node.FirstChild.InnerText); } Console.WriteLine("==================================="); return 20; } }
This would produce:
First Child Inner Text: The Distinguished Gentleman First Child Inner Text: Her Alibi First Child Inner Text: Chalte Chalte =================================== Press any key to continue . . .
In this example, we started our parsing on the root node of the document. At times, you will need to consider only a particular node, such as the first child of a node. For example, you may want to use only the first child of the root. To get it, you can access the FirstChild property of the DocumentElement object of the DOM. Once you get that node, you can then do what you judge necessary.
Consider the following modification of the Videos.xml file:
<?xml version="1.0" encoding="utf-8" ?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<CastMembers>
<Actor>Eddie Murphy</Actor>
<Actor>Lane Smith</Actor>
<Actor>Sheryl Lee Ralph</Actor>
<Actor>Joe Don Baker</Actor>
<Actor>Victoria Rowell</Actor>
</CastMembers>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
<Video>
<Title>Chalte Chalte</Title>
<Director>Aziz Mirza</Director>
<Length>145 Mins</Length>
<Format>DVD</Format>
<Rating>N/R</Rating>
</Video>
</Videos>
In the following example, only the values of the child nodes of the first child of the root are displayed:
using System; using System.IO; using System.Xml; public class Exercise { public static int Main(string[] args) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); // Locate the root node and // get a reference to its first child XmlNode node = xdVideos.DocumentElement.FirstChild; // Create a list of the child nodes of // the first node under the root XmlNodeList xnlVideos = node.ChildNodes; // Visit each node for (int i = 0; i < xnlVideos.Count; i++) { // Look for a node named CastMembers if (xnlVideos[i].Name == "CastMembers") { // Once/if you find it, // 1. Access its first child // 2. Create a list of its child nodes XmlNodeList xnlActors = xnlVideos[i].ChildNodes; // Display the values of the nodes for (int j = 0; j < xnlActors.Count; j++) Console.WriteLine(string.Format("Inner Text: {0}", xnlActors[j].InnerText)); } } } Console.WriteLine("==================================="); return 10; } }
This would produce:
Inner Text: Eddie Murphy Inner Text: Lane Smith Inner Text: Sheryl Lee Ralph Inner Text: Joe Don Baker Inner Text: Victoria Rowell =================================== Press any key to continue . . .
The Content of the First Child Node
Remember that when using a loop (for or foreach) applied to an XmlNodeList collection, each node that you access is a complete XmlNode object and may have children. This means that you can further get the ChildNodes node of any node. Here is an example that primarily scans the nodes but looks for one whose name is CastMembers:
using System.IO; using System.Xml; using static System.Console; public class Exercise { public static int Main(string[] args) { XmlDocument xdVideos = new XmlDocument(); string strVideosFile = @"C:\Videos Collection\Videos.xml"; if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); // Locate the root node and // get a reference to its first child XmlNode node = xdVideos.DocumentElement.FirstChild; // Create a list of the child nodes of // the first node under the root XmlNodeList xnlVideos = node.ChildNodes; // Visit each node for (int i = 0; i < xnlVideos.Count; i++) { // Look for a node named CastMembers if (xnlVideos[i].Name == "CastMembers") { // Once/if you find it, // 1. Access its first child // 2. Create a list of its child nodes XmlNodeList xnlActors = xnlVideos[i].ChildNodes; // Display the values of the nodes for (int j = 0; j < xnlActors.Count; j++) WriteLine("Inner Text: {0}", xnlActors[j].InnerText); } } } WriteLine("==================================="); return 10; } }
We have learned that a node or a group of nodes can be nested inside of another node. When you get to a node, you may know or find out that it has children. You may then want to consider only the first child. Here is an example:
using System.IO;
using System.Xml;
using static System.Console;
public class Exercise
{
public static int Main(string[] args)
{
string strVideosFile = @"C:\Videos Collection\Videos.xml";
XmlDocument xdVideos = new XmlDocument();
if (File.Exists(strVideosFile))
{
xdVideos.Load(strVideosFile);
// Locate the root node and
// get a reference to its first child
XmlNode node = xdVideos.DocumentElement.FirstChild;
// Create a list of the child nodes of
// the first node under the root
XmlNodeList xnlVideos = node.ChildNodes;
// Visit each node
for (int i = 0; i < xnlVideos.Count; i++)
{
// Look for a node named CastMembers
if (xnlVideos[i].Name == "CastMembers")
{
// Once/if you find it,
// 1. Access its first child
// 2. Create a list of its child nodes
XmlNodeList xnlActors = xnlVideos[i].FirstChild.ChildNodes;
// Display the value of its first child node
for (int j = 0; j < xnlActors.Count; j++)
WriteLine(string.Format("Actor: {0}", @xnlActors[j].InnerText));
}
}
}
WriteLine("===================================");
return 10;
}
}
This would produce:
Actor: Eddie Murphy =================================== Press any key to continue . . .
The Siblings of a Node
Introduction
The child nodes that are nested in a parent node and share the same level are referred to as siblings.
The Next Sibling
To let you access the sibling of a node, the XmlNode class provides a property named NextSibling. It is declared as follows:
public virtual XmlNode NextSibling { get; }
Inserting an Element Before a Sibling
Instead of simply adding a new node at the end of child nodes, you can specify any other position you want. For example, you may want the new node to precede an existing child node. To support this operation, the XmlNode class is equipped with a method named InsertBefore. Its syntax is:
public virtual XmlNode InsertBefore(XmlNode newChild, XmlNode refChild);
The first argument of this method is the new node that will be added. The second argument is the sibling that will succeed the new node. Consider the following version of our Videos.xml file:
<?xml version="1.0" encoding="utf-8"?> <videos> <video> <title>The Distinguished Gentleman</title> <director>Jonathan Lynn</director> <length>112 Minutes</length> <format>DVD</format> <rating>R</rating> <category>Comedy</category> </video> <video> <title>Fatal Attraction</title> <director>Adrian Lyne</director> <length>119 Minutes</length> <format>DVD</format> <rating>R</rating> </video> </videos>
Imagine you want to create a new category element below the director element whose name is Adrian Lyne. You can first get a list of videos. Inside of each video, check the nodes and find out whether the video has a director node whose text is Adrian Lyne. Once you find that node, you can add the new element after it. Here is an example:
using System.IO; using System.Xml; public class Exercise { public static int Main(string[] args) { string strVideosFile = @"C:\Videos Collection\Videos.xml"; XmlDocument xdVideos = new XmlDocument(); if (File.Exists(strVideosFile)) { xdVideos.Load(strVideosFile); // Get a reference to the root node XmlElement xeRoot = xdVideos.DocumentElement; // Create a list of the videos XmlNodeList xnlVideos = xdVideos.GetElementsByTagName("video"); // visit each video foreach (XmlNode node in xnlVideos) { // Within a video, create a list of its children XmlNodeList lstChildren = node.ChildNodes; // Visit each child node foreach (XmlNode dir in lstChildren) { // If the child node is (a director and its name is) Adrian Lyne if (dir.InnerText == "Adrian Lyne") { // Create an element named Category XmlElement xeNewVideo = xdVideos.CreateElement("category"); // Specify the text of the new element xeNewVideo.InnerText = "Drama"; // Insert the new node below the Adrian Lyne node Director node.InsertAfter(xeNewVideo, dir); // Save the file xdVideos.Save(strVideosFile); // Stop looking for the child node break; } } } } return 10203; } }
This would produce:
<?xml version="1.0" encoding="utf-8"?>
<videos>
<video>
<title>The Distinguished Gentleman</title>
<director>Jonathan Lynn</director>
<length>112 Minutes</length>
<format>DVD</format>
<rating>R</rating>
<category>Comedy</category>
</video>
<video>
<title>Fatal Attraction</title>
<director>Adrian Lyne</director>
<category>Drama</category>
<length>119 Minutes</length>
<format>DVD</format>
<rating>R</rating>
</video>
</videos>
In the same way, you can insert a new node after a child of a child (or of a child of a child of a child) of any node.
To let you position a new node after an existing child node, the XmlNode class is equipped with a method named InsertAfter. Its syntax is:
public virtual XmlNode InsertAfter(XmlNode newChild, XmlNode refChild);
|
||
Previous | Copyright © 2005-2021, FunctionX | Next |
|