Adding an Element in a Grid Sheet |
|
The
easiest way to add text to an element, whether the element exists already or you
want to add a new element, consists of manually opening the file and typing the text of the
new element in the desired section. For example, you can click the Data button
of the XML while opened in Visual Studio .NET:
If you click the empty cells and fill them up, if you save
the file, the new elements would be added to the file.
Practical Learning: Adding Elements in the Data Grid
|
|
- Display the Employees.xml file and click its Data button
- Click the first empty cell under the EmplNumber column and type 24-705
- Click the first empty cell under the FirstName column and type Gertrude
- Press Tab and type Monay
- Press Tab and type 14.66 and press Enter
- Press Ctrl + S to save the file
- Click the XML button and notice the new record has been added
To programmatically create a new element, you can declare an
XmlElement variable. To add the new element to the file, the XmlDocument
class provides the CreateElement() method that is overloaded with three
versions. One of the versions uses the following syntax:
public XmlElement CreateElement(string name);
Using this method, to create a new element, call it and pass it the name of the new element. If you want the element to
have a value, the XmlDocument class is equipped with the CreateTextNode()
method. 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. The calls to XmlDocument.CreateElement()
and XmlDocument.CreateTextNode() allow you to initialize a new element.
In order to actually add the new element, you must specify its position in the
tree: whether it would be the first or the last node, whether you want to
position it before or after a node of your choice. To support the positions of
existing nodes, the XmlNode class, which is the ancestor of all XML nodes
of the .NET Framework, provides various appropriate methods.
One of these methods is AppendChild(), which is
used to add an element as the last child of its parent. The syntax of the XmlNode.AppendChild()
method is:
public virtual XmlNode AppendChild(XmlNode newChild);
Imagine you have a simple XML file that has only the root
and one level
of elements as follows:
<?xml version="1.0" encoding="utf-8"?>
<Holidays>
<Holiday>New Year's Day</Holiday>
<Holiday>Birthday of Martin Luther King, Jr.</Holiday>
<Holiday>Washington's Birthday</Holiday>
</Holidays>
To add a new Holiday element to this file, based on the
above discussions, you can use code as follows:
private void btnAddHoliday_Click(object sender, System.EventArgs e)
{
XmlDocument docXML = new XmlDocument();
docXML.Load("Holidays.xml");
XmlElement elmXML = docXML.CreateElement("Holiday");
XmlText txtXML = docXML.CreateTextNode("Memorial Day");
docXML.DocumentElement.AppendChild(elmXML);
docXML.DocumentElement.LastChild.AppendChild(txtXML);
docXML.Save("Holidays.xml");
}
Practical Learning: Adding Elements
|
|
- To add a new form, on the main menu, click Project -> Add Windows
Form...
- In the Templates list of the Add New Item dialog box, make sure that Windows Forms
(.NET) is selected.
Set the Name to NewMake and press Enter
- Design the form as follows:
|
Control |
Name |
Text |
Other Properties |
Label |
|
New Car Make: |
|
TextBox |
txtNewMake |
|
Modifiers: Public |
Button |
btnOK |
OK |
DialogResult: OK |
Button |
btnCancel |
Cancel |
DialogResult: Cancel |
Form |
|
New Make |
AcceptButton: btnOK
CancelButton: btnCancel
FormBorderStyle: FixedDialog
MaximizeBox: False
MinimizeBox: False
ShowInTaskbar: False
StartPosition: CenterScreen |
|
- Display the first or main form (Form1.cs [Design]) and add a new Button
control to it
- Set its Name to btnNewMake and its Text to New Make
- Double-click the New Make button
- In the top section of the file, under the other using lines, type:
using System.Xml;
- Implement its Click event as follows:
private void btnNewMake_Click(object sender, System.EventArgs e)
{
// The new car make will come from the New Make dialog box
NewMake frmMake = new NewMake();
// Display the New Make dialog box and find out if the user clicked OK
if( frmMake.ShowDialog() == DialogResult.OK )
{
string strNewMake = frmMake.txtNewMake.Text;
// If the New Make string is empty, don't do anything
if( strNewMake.Equals("") )
return;
// Open the Makes.xml file
XmlDocument docXMLFile = new XmlDocument();
docXMLFile.Load("Makes.xml");
// Get the root node so we can explore its children
XmlElement nodRoot = docXMLFile.DocumentElement;
// Store all the values of the elements in a string
string allMyChildren = nodRoot.InnerText;
// Locate the new make among the values of the elements
int indexLookForNewMake = allMyChildren.IndexOf(strNewMake);
// If the car make exists already, don't add it
if( indexLookForNewMake >= 0 )
return;
else
{
// If the car is not in the list already, add it as a Make element
XmlElement elmXML = docXMLFile.CreateElement("Make");
// Create its value using the string from the New Make dialog box
XmlText txtXML = docXMLFile.CreateTextNode(frmMake.txtNewMake.Text);
// Add the new element at the end of the file
docXMLFile.DocumentElement.AppendChild(elmXML);
// Specify its text
docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);
// Save the file
docXMLFile.Save("Makes.xml");
}
}
}
|
- To add a new form, on the main menu, click Project -> Add Windows
Form...
- In the Templates list of the Add New Item dialog box, make sure that Windows Forms
(.NET) is selected.
Set the Name to NewModel and press Enter
- Design the form as follows:
|
Control |
Name |
Text |
Other Properties |
Label |
|
New Car Model: |
|
TextBox |
txtNewModel |
|
|
Button |
btnOK |
OK |
DialogResult: OK |
Button |
btnCancel |
Cancel |
DialogResult: Cancel |
Form |
|
New Car Model |
AcceptButton: btnOK
CancelButton: btnCancel
FormBorderStyle: FixedDialog
MaximizeBox: False
MinimizeBox: False
ShowInTaskbar: False
StartPosition: CenterScreen |
|
- Display the first or main form (Form1.cs [Design]) and add a new Button
control to it
- Set its Name to btnNewModel and its Text to New Car Model
- Double-click the New Car Model button and implement its Click event as
follows:
private void btnNewModel_Click(object sender, System.EventArgs e)
{
// The new car make will come from the New Make dialog box
NewModel frmModel = new NewModel();
// Display the New Make dialog box and find out if the user clicked OK
if( frmModel.ShowDialog() == DialogResult.OK )
{
string strNewModel = frmModel.txtNewModel.Text;
// If the New Make string is empty, don't do anything
if( strNewModel.Equals("") )
return;
// Open the Makes.xml file
XmlDocument docXMLFile = new XmlDocument();
docXMLFile.Load("Models.xml");
// Get the root node so we can explore its children
XmlElement nodRoot = docXMLFile.DocumentElement;
// Store all the values of the elements in a string
string allMyChildren = nodRoot.InnerText;
// Locate the new make among the values of the elements
int indexLookForNewModel = allMyChildren.IndexOf(strNewModel);
// If the car make exists already, don't add it
if( indexLookForNewModel >= 0 )
return;
else
{
// If the car is not in the list already, add it as a Make element
XmlElement elmXML = docXMLFile.CreateElement("Model");
// Create its value using the string from the New Make dialog box
XmlText txtXML = docXMLFile.CreateTextNode(frmModel.txtNewModel.Text);
// Add the new element at the end of the file
docXMLFile.DocumentElement.AppendChild(elmXML);
// Specify its text
docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);
// Save the file
docXMLFile.Save("Models.xml");
}
}
}
|
- Execute the application to test it
- Try adding one or two more car manufacturers like Toyota and Dodge
- Try adding an existing make to notice that it cannot be added twice
- Try adding one or more new car models such as Integra and 328I
Adding a Filled Child Element |
|
The above Holidays.xml file had only one level under the
root and no child element of the root had children. Suppose you have a file
as follows:
<?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>
</Videos>
Imagine that you want to add a Video element. You have a
choice of adding one, more, or all child elements of the Video node. To perform
this operation, one solution you can use is to "build" all child
elements of the Video element, then add the node as a whole. To support this
technique, we saw earlier that the XmlNode.InnerXml property comprises a
node, its markup, its children and their markup. This means that you can create
the child nodes with their markup(s) as a string and assign that string to an XmlNode.InnerXml
string. To do this, you would need the set version of the InnerXml
property. It is declared as follows:
public virtual string InnerXml{get; set;}
Here is an example that adds a complete new Video node to
the above XML file:
private void button1_Click(object sender, System.EventArgs e)
{
XmlDocument docXML = new XmlDocument();
docXML.Load("Videos.xml");
XmlElement elmXML = docXML.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>";
elmXML.InnerXml = strNewVideo;
docXML.DocumentElement.AppendChild(elmXML);
docXML.Save("Videos.xml");
}
If you have an XML file with different levels and you want to
add an element as a new child to a particular element, you can first locate that
element. One way you can do this is to call the XmlDocument.GetElementByTagName()
method. This method is overloaded with two versions. One of its versions has
the following syntax:
public virtual XmlNodeList GetElementsByTagName(string name);
This method takes as argument the name of the element that
you want to locate. If the method finds that element, it returns a list of all
child nodes of that element as an XmlNodeList object. This XmlNodeList
object represents a collection of nodes where each node can be located by its
index through the ItemOf indexed property.
Practical Learning: Adding Elements
|
|
- Add a new Windows Form named NewPart
- Design the form as follows:
|
Control |
Name |
Text |
Other Properties |
Label |
|
Year: |
|
ComboBox |
cboYears |
|
DropDownStyle: DropDownList
Modifiers: Public |
Label |
|
Make: |
|
ComboBox |
cboMakes |
|
DropDownStyle: DropDownList
Modifiers: Public |
Button |
btnNewMake |
New Make |
|
Label |
|
Model: |
|
ComboBox |
cboModels |
|
DropDownStyle: DropDownList
Modifiers: Public |
Button |
btnNewModel |
New Model |
|
Label |
|
Part Name: |
|
TextBox |
txtPartName |
|
Modifiers: Public |
Label |
|
Unit Price: |
|
TextBox |
txtUnitPrice |
0.00 |
Modifiers: Public
TextAlign: Right |
Label |
|
Part #: |
|
TextBox |
txtPartNumber |
000000 |
Modifiers: Public
TextAlign: Right |
Button |
btnAddPart |
Add Part |
|
Button |
btnClose |
Close |
|
Form |
|
|
AcceptButton: btnAddPart
CancelButton: btnClose
MaximizeBox: False
StartPosition: CenterScreen |
|
- Double-click an unoccupied area of the form to access its Load event
- In the top section of the file, under the other using lines, type:
using System.Xml;
- Implement the Load as follows:
private void NewPart_Load(object sender, System.EventArgs e)
{
// Fill the Year combo box with years from 1960 to the coming year
for(int i = DateTime.Now.Year+1; i >= 1960; i--)
this.cboYears.Items.Add(i.ToString());
// We will need a reference to the XML document
XmlDocument docXML = new XmlDocument();
// Open the Makes.xml file
docXML.Load("Makes.xml");
// Get a reference to the root node
XmlElement nodRoot = docXML.DocumentElement;
// Locate all nodes whose name is Make
XmlNodeList nodItems = nodRoot.GetElementsByTagName("Make");
// Retrieve the value of each Make node and put
// that value in the Make combo box
for(int i = 0; i < nodItems.Count; i++)
this.cboMakes.Items.Add(nodItems[i].InnerXml);
// Open the Models.xml file
docXML.Load("Models.xml");
// Get a reference to the root node
nodRoot = docXML.DocumentElement;
// Locate all nodes whose name is Make
nodItems = nodRoot.GetElementsByTagName("Model");
// Retrieve the value of each Make node and put
// that value in the Make combo box
for(int i = 0; i < nodItems.Count; i++)
this.cboModels.Items.Add(nodItems[i].InnerXml);
// We will generate a random number for the item
// To start, we will use the miliseconds as a seed
DateTime curTime = DateTime.Now;
int ms = curTime.Millisecond;
// Now we can generate a random number between 100000 and 999999
Random rndNumber = new Random(ms);
int next = rndNumber.Next(100000, 999999);
// Display the new number in the Part # text box
this.txtPartNumber.Text = next.ToString();
// Disable the OK button to indicate that the part is not ready
this.btnAddPart.Enabled = false;
}
|
- Display the form again and double-click the New Make button
- Implement its Click event as follows:
private void btnNewMake_Click(object sender, System.EventArgs e)
{
// The new car make will come from the New Make dialog box
NewMake frmMake = new NewMake();
// Display the New Make dialog box and find out if the user clicked OK
if( frmMake.ShowDialog() == DialogResult.OK )
{
string strNewMake = frmMake.txtNewMake.Text;
// If the New Make string is empty, don't do anything
if( strNewMake.Equals("") )
return;
// Before adding the new make, check that it doesn't exist already
if( this.cboMakes.FindStringExact(strNewMake) > 0 )
return;
// Now you can add it
this.cboMakes.Items.Add(strNewMake);
// The user likely wants this new item selected
this.cboMakes.Text = strNewMake;
// -- There are other ways you can add the new make to the Makes.xml file...
// We are using the following approach because it allows different people
// who are accessing the same file from different computers to update it
// without having to lock the file
// Open the Makes.xml file
XmlDocument docXMLFile = new XmlDocument();
docXMLFile.Load("Makes.xml");
// Get the root node so we can explore its children
XmlElement nodRoot = docXMLFile.DocumentElement;
// If the car is not in the list already, add it as a Make element
XmlElement elmXML = docXMLFile.CreateElement("Make");
// Create its value using the string from the New Make dialog box
XmlText txtXML = docXMLFile.CreateTextNode(strNewMake);
// Add the new element at the end of the file
docXMLFile.DocumentElement.AppendChild(elmXML);
// Specify its text
docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);
// Save the file
docXMLFile.Save("Makes.xml");
}
}
|
- Display the form again and double-click the New Model button
- Implement its Click event as follows:
private void btnNewModel_Click(object sender, System.EventArgs e)
{
// The new car make will come from the New Make dialog box
NewModel frmModel = new NewModel();
// Display the New Make dialog box and find out if the user clicked OK
if( frmModel.ShowDialog() == DialogResult.OK )
{
string strNewModel = frmModel.txtNewModel.Text;
// If the New Make string is empty, don't do anything
if( strNewModel.Equals("") )
return;
// Before adding the new make, check that it doesn't exist already
if( this.cboModels.FindStringExact(strNewModel) > 0 )
return;
// Now you can add it
this.cboModels.Items.Add(strNewModel);
// The user likely wants this new item selected
this.cboModels.Text = strNewModel;
// -- There are other ways you can add the new make to the Makes.xml file...
// We are using the following approach because it allows different people
// who are accessing the same file from different computers to update it
// without having to lock the file
XmlDocument docXMLFile = new XmlDocument();
// Open the Makes.xml file
docXMLFile = new XmlDocument();
docXMLFile.Load("Models.xml");
// Get the root node so we can explore its children
XmlElement nodRoot = docXMLFile.DocumentElement;
// If the model is not in the list already, add it as a Model element
XmlElement elmXML = docXMLFile.CreateElement("Model");
// Create its value using the string from the New Make dialog box
XmlText txtXML = docXMLFile.CreateTextNode(strNewModel);
// Add the new element at the end of the file
docXMLFile.DocumentElement.AppendChild(elmXML);
// Specify its text
docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);
// Save the file
docXMLFile.Save("Models.xml");
}
}
|
- Return to the form and double-click the Part Name text box
- Implement its TextChanged event as follows:
private void txtPartName_TextChanged(object sender, System.EventArgs e)
{
// If there is no part name, no need to add the item to the XML file
if( this.txtPartName.Text.Equals("") )
this.btnAddPart.Enabled = false;
else
this.btnAddPart.Enabled = true;
}
|
- Return to the form and double-click the Unit Price text box
- Implement its TextChanged event as follows:
private void txtUnitPrice_TextChanged(object sender, System.EventArgs e)
{
// If the price is not specified, don't add the item to the XML file
if( this.txtUnitPrice.Text.Equals("") )
this.btnAddPart.Enabled = false;
else
this.btnAddPart.Enabled = true;
}
|
- Return to the form and double-click the Part # text box
- Implement its TextChanged event as follows:
private void txtPartNumber_TextChanged(object sender, System.EventArgs e)
{
// Make sure that there is a Part Number for this item
// Otherwise, don't add the part to the XML file
try
{
if( (this.txtPartNumber.Text.Equals("")) ||
(int.Parse(this.txtPartNumber.Text) < 100000) ||
(int.Parse(this.txtPartNumber.Text) > 999999) )
this.btnAddPart.Enabled = false;
else
this.btnAddPart.Enabled = true;
}
catch(FormatException )
{
MessageBox.Show("Only numbers are allowed");
this.txtPartNumber.Text = "";
this.txtPartNumber.Focus();
}
}
|
- Display the first or main form (Form1.cs [Design]) and add a new Button
control to it
- Set its Name to btnNewPart and its Text to New Part
- Double-click the New Car Model button and implement its Click event as
follows:
private void btnNewPart_Click(object sender, System.EventArgs e)
{
NewPart frmNewPart = new NewPart();
if( frmNewPart.ShowDialog() == DialogResult.OK )
{
string strPartNumber = frmNewPart.txtPartNumber.Text;
string strCarYear = frmNewPart.cboYears.Text;
string strMake = frmNewPart.cboMakes.Text;
string strModel = frmNewPart.cboModels.Text;
string strPartName = frmNewPart.txtPartName.Text;
string strUnitPrice = frmNewPart.txtUnitPrice.Text;
if( strCarYear.Equals("") )
return;
if( strMake.Equals("") )
return;
if( strModel.Equals("") )
return;
XmlDocument docXML = new XmlDocument();
docXML.Load("Parts.xml");
XmlElement elmXML = docXML.CreateElement("Part");
string strNewPart = "<PartNumber>" + strPartNumber + "</PartNumber>" +
"<CarYear>" + strCarYear + "</CarYear>" +
"<Make>" + strMake + "</Make>" +
"<Model>" + strModel + "</Model>" +
"<PartName>" + strPartName + "</PartName>" +
"<UnitPrice>" + strUnitPrice + "</UnitPrice>";
elmXML.InnerXml = strNewPart;
docXML.DocumentElement.AppendChild(elmXML);
docXML.Save("Parts.xml");
}
}
private void btnClose_Click(object sender, System.EventArgs e)
{
Close();
}
|
- Execute the application to test it
- Try adding a new part to the Parts.xml file using the New Part dialog box
accessed from the main form
An XML tree navigation consists of visiting the various
nodes of the file, for any necessary reason. One reason would be that you want
to insert a new element at a specific position in the tree. Another would be
that you want to check whether a certain node is already present in the tree.
As always, there are various ways you can perform an
operation such as navigating a tree. To "scan" a file from top to
bottom, thus visiting each type of node in the XML file, you can use the XmlTextReader
class. This class is equipped with all types of properties and methods you would
need.
If you want to navigate to a specific node in the tree, you
can use the XmlDocument.GetElementByTagName() method that we used
previously.
|
|