Home

Introduction

 

Fundamentals

 

Introduction

 

 

     
 
 

 

   
   
 

Previous Copyright © 2015 FunctionX Next

Home

Operations on XML Elements

 

Creating an XML Element

 

Introduction

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 all types of routine operations of an XML document, an element, or a node. The operations include locating a node, adding a new element, or deleting a node.

Before performing an operation, you will usually need to decide in what section of the document you want the action to be applied. As it happens, you have the root node, a particular node inside the document, a parent of a certain 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.

Creating an Element

To assist with programmatically creating a new element, the XmlDocument class is equipped with a method named CreateElement that is overloaded with three versions. One of the versions uses the following signature:

member CreateElement : 
        name:string -> XmlElement

To create a new element, call this method and pass it the name of the element. Here is an example:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// Button: New Road
 let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                             Text = "New Road", Size = new System.Drawing.Size(145, 36),
                             Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads.xml"

    if File.Exists(strRoadsFile) then
        use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        xdRoads.Load fsRoads
        fsRoads.Close()
        
        let xeRoad : XmlElement = xdRoads.CreateElement "road"
        
btnNewRoad.Click.Add btnNewRoadClick

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

Appending an Element

In order to add the new element to the document, 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, etc. For example, if you want to add a new road element to the above document, it would be considered a child of the root, that is, a child of the XmlDocument.DocumentElement property.

To support the positions of existing nodes, the XmlNode class, which is the ancestor to all XML nodes of the .NET Framework, provides various appropriate methods. One of these methods is named AppendChild. It is used to add an element as the last child of its parent. The signature of the XmlNode.AppendChild() method is:

abstract AppendChild : 
        newChild:XmlNode -> XmlNode  
override AppendChild : 
        newChild:XmlNode -> XmlNode

When calling this method, pass the XmlNode object you had previous created. Here is an example:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")


let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                            Text = "New Road", Size = new System.Drawing.Size(145, 36),
                            Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads.xml"

    if File.Exists(strRoadsFile) then
        use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        xdRoads.Load fsRoads
        fsRoads.Close()
        
        let xeRoad : XmlElement = xdRoads.CreateElement "road"
        let xnRoad = xdRoads.DocumentElement.AppendChild xeRoad        

btnNewRoad.Click.Add btnNewRoadClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

After adding the node, if you want to keep it, you should save the file. Consider the following file named Roads1.xml:

<?xml version="1.0" encoding="utf-8"?>
<roads />

Here is an example that supposes that the XML file exists already:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// Button: New Road
let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                          Text = "New Road", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads1.xml"

    if File.Exists(strRoadsFile) then
        use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        xdRoads.Load fsRoads
        fsRoads.Close()
        
        let xeRoad : XmlElement = xdRoads.CreateElement "road"
        let xnRoad = xdRoads.DocumentElement.AppendChild xeRoad
        
        use fsRoads = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
        xdRoads.Save fsRoads
        fsRoads.Close()

btnNewRoad.Click.Add btnNewRoadClick

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(12, 54),
                          Text = "Close", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnClose

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<roads>
  <road />
</roads>

Here is an example that first checks whether the file exists already or not. If the file doesn't exist, the code creates a primary XML file with the necessary basic tags:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// Button: New Road
let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                          Text = "New Road", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads1.xml"

    if File.Exists(strRoadsFile) = false then
        xdRoads.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                        "<roads />")

 	use fsRoads = new FileStream(strRoadsFile, FileMode.CreateNew, FileAccess.Write)
        xdRoads.Save fsRoads
        fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
    xdRoads.Load fsRoads
    fsRoads.Close()
        
    let xeRoad : XmlElement = xdRoads.CreateElement "road"
    let xnRoad = xdRoads.DocumentElement.AppendChild xeRoad
        
    use fsRoads = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
    xdRoads.Save fsRoads
    fsRoads.Close()

btnNewRoad.Click.Add btnNewRoadClick

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(12, 54),
                          Text = "Close", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnClose

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

This time, the result is:

<?xml version="1.0" encoding="utf-8"?>
<roads>
  <road />
  <road />
</roads>

Notice that, in both cases, the newly added element is empty.

As you might have realized, it is very easy to create an element. This is done in two simple steps:

Probably the only real concern you will have here is to specify what node will own the new element. To locate a node, you can use its position in the collection of nodes or you can get a list of nodes that use a certain name. As we know already, this can be done by calling the XmlDocument.GetElementsByTagName() method. From there, by using a loop or any technique of your choice, you can locate the node you want. You can then decide whether the new element will be a child of that node, or you can decide that the new node would be created on the same level as the node, or on the same level as parent node, etc. Consider the following file named Roads2.xml:

<?xml version="1.0" encoding="utf-8"?>
<roads>
  <road>
    <road-name>MD 410</road-name>
    <road-type>Road</road-type>
    <distance>13.920</distance>
    <location>From East Bethesda to Pennsy Drive in Landover Hills</location>
  </road>
  <road>
    <road-name>I-81</road-name>
    <road-type>Interstate</road-type>
    <distance>855</distance>
    <location>From Dandridge, TN to Wellesley Island, NY/Hill Island, ON</location>
  </road>
  <road>
    <road-name>US 75</road-name>
    <road-type>Road</road-type>
    <distance>1239</distance>
    <location>From Dallas, TX to Moorhead, MN</location>
  </road>
</roads>

Here is an example that add a new element to a node gotten from its tag name:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// Button: New Road
let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                          Text = "New Road", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads2.xml"

    if File.Exists(strRoadsFile) = false then
        xdRoads.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                        "<roads />")

        use fsRoads = new FileStream(strRoadsFile, FileMode.CreateNew, FileAccess.Write)
        xdRoads.Save fsRoads
        fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
    xdRoads.Load fsRoads
    fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
    let xnlRoads : XmlNodeList = xdRoads.GetElementsByTagName "road-name"
        
    for xnRoad in xnlRoads do
        if xnRoad.InnerText = "I-81" then
            let xeRoad : XmlElement = xdRoads.CreateElement "road"
            let xnTemp = xnRoad.ParentNode.ParentNode.AppendChild xeRoad
        
            xdRoads.Save fsRoads
    fsRoads.Close()

btnNewRoad.Click.Add btnNewRoadClick

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(12, 54),
                          Text = "Close", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnClose

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<roads>
  <road>
    <road-name>MD 410</road-name>
    <road-type>Road</road-type>
    <distance>13.920</distance>
    <location>From East Bethesda to Pennsy Drive in Landover Hills</location>
  </road>
  <road>
    <road-name>I-81</road-name>
    <road-type>Interstate</road-type>
    <distance>855</distance>
    <location>From Dandridge, TN to Wellesley Island, NY/Hill Island, ON</location>
  </road>
  <road>
    <road-name>US 75</road-name>
    <road-type>Road</road-type>
    <distance>1239</distance>
    <location>From Dallas, TX to Moorhead, MN</location>
  </road>
  <road />
</roads>

On the other hand, if you want to add a new element to a node, after getting a reference to that node, get a reference to its parent and call the AppendChild(). Here is an example:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// Button: New Road
let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                          Text = "New Road", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads2.xml"

    if File.Exists(strRoadsFile) = false then
        xdRoads.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                        "<roads />")

        use fsRoads = new FileStream(strRoadsFile, FileMode.CreateNew, FileAccess.Write)
        xdRoads.Save fsRoads
        fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
    xdRoads.Load fsRoads
    fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
    let xnlRoads : XmlNodeList = xdRoads.GetElementsByTagName "road-name"
        
    for xnRoad in xnlRoads do
        if xnRoad.InnerText = "I-81" then
            let xeIntersection : XmlElement = xdRoads.CreateElement "intersection"
            let xnTemp = xnRoad.ParentNode.AppendChild xeIntersection

            xdRoads.Save fsRoads
    fsRoads.Close()

btnNewRoad.Click.Add btnNewRoadClick

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(12, 54),
                          Text = "Close", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnClose

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<roads>
  <road>
    <road-name>MD 410</road-name>
    <road-type>Road</road-type>
    <distance>13.920</distance>
    <location>From East Bethesda to Pennsy Drive in Landover Hills</location>
  </road>
  <road>
    <road-name>I-81</road-name>
    <road-type>Interstate</road-type>
    <distance>855</distance>
    <location>From Dandridge, TN to Wellesley Island, NY/Hill Island, ON</location>
    <intersection />
  </road>
  <road>
    <road-name>US 75</road-name>
    <road-type>Road</road-type>
    <distance>1239</distance>
    <location>From Dallas, TX to Moorhead, MN</location>
  </road>
  <road />
</roads>

Adding the Inner Text of an Element

We already know that the XmlNode.InnerXml property includes a node, its markup, its child(ren) and their markup. This means that you can create the child node(s) with its (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:

abstract InnerXml : string with get, set 
override InnerXml : string with get, set

Here is an example that adds a new road node to the above XML file:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// Button: New Road
let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                          Text = "New Road", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads3.xml"

    if File.Exists(strRoadsFile) = false then
        xdRoads.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                        "<roads />")

        use fsRoads = new FileStream(strRoadsFile, FileMode.CreateNew, FileAccess.Write)
        xdRoads.Save fsRoads
        fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
    xdRoads.Load fsRoads
    fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
    
    let xeRoad : XmlElement = xdRoads.CreateElement "road"
    xeRoad.InnerXml <- "<road-name>I-85</road-name>" +
                       "<road-type>Interstate</road-type>" +
                       "<distance>668.75</distance>" +
                       "<location>From Montgomery, AL on I-65 to Petersburg, VA (near Richmond) on I-95</location>" +
                       "<intersections />"
    let xnCreated = xdRoads.DocumentElement.AppendChild xeRoad

    xdRoads.Save fsRoads
    fsRoads.Close()

btnNewRoad.Click.Add btnNewRoadClick

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(12, 54),
                          Text = "Close", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnClose

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<roads>
  <road>
    <road-name>I-85</road-name>
    <road-type>Interstate</road-type>
    <distance>668.75</distance>
    <location>From Montgomery, AL on I-65 to Petersburg, VA (near Richmond) on I-95</location>
    <intersections />
  </road>
</roads>

In the same way, you can provide thhe whole structure of an element including its children. Here is an example:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(328, 145),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// Button: New Road
let btnNewRoad = new Button(Location = new System.Drawing.Point(12, 12),
                          Text = "New Road", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = "../../Roads3.xml"

    if File.Exists(strRoadsFile) = false then
        xdRoads.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                        "<roads />")

        use fsRoads = new FileStream(strRoadsFile, FileMode.CreateNew, FileAccess.Write)
        xdRoads.Save fsRoads
        fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
    xdRoads.Load fsRoads
    fsRoads.Close()

    use fsRoads = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
    
    let xeRoad : XmlElement = xdRoads.CreateElement "road"
    xeRoad.InnerXml <- "<road-name>WYO 789</road-name>" +
                       "<road-type>State Highway</road-type>" +
                       "<distance>404</distance>" +
                       "<location>From Colorado to Montana</location>" +
                       "<intersections>" +
                       "     <intersection>" +
                       "         <intersecting>SH 13</intersecting>" +
                       "         <in-near>Baggs, CO</in-near>" +
                       "     </intersection>" +
                       "     <intersection>" +
                       "         <intersecting>I-80/US 30</intersecting>" +
                       "         <in-near>Creston Junction</in-near>" +
                       "     </intersection>" +
                       "     <intersection>" +
                       "         <intersecting>US 287</intersecting>" +
                       "         <in-near>Rawlins, WY</in-near>" +
                       "     </intersection>" +
                       "</intersections>"
    let xnCreated = xdRoads.DocumentElement.AppendChild xeRoad

    xdRoads.Save fsRoads
    fsRoads.Close()

btnNewRoad.Click.Add btnNewRoadClick

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(12, 54),
                          Text = "Close", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnClose

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<roads>
    <road>
	<road-name>I-85</road-name>
	<road-type>Interstate</road-type>
	<distance>668.75</distance>
	<location>From Montgomery, AL on I-65 to Petersburg, VA (near Richmond) on I-95</location>
	<intersections />
    </road>
    <road>
	<road-name>WYO 789</road-name>
	<road-type>State Highway</road-type>
	<distance>404</distance>
	<location>From Colorado to Montana</location>
	<intersections>
	    <intersection>
		<intersecting>SH 13</intersecting>
		<in-near>Baggs, CO</in-near>
	    </intersection>
	    <intersection>
		<intersecting>I-80/US 30</intersecting>
		<in-near>Creston Junction</in-near>
	    </intersection>
	    <intersection>
		<intersecting>US 287</intersecting>
		<in-near>Rawlins, WY</in-near>
	    </intersection>
	</intersections>
    </road>
</roads>

(When you open this file, if you are using Microsoft Visual Studio, delete the last > as in </roads. Then type it again to get </roads>. OR, change the code as follows:

xeRoad.InnerXml <- "<road-name>WYO 789</road-name>" +
                   "<road-type>State Highway</road-type>" +
                   "<distance>404</distance>" +
                   "<location>From Colorado to Montana</location>" +
                   "<intersections>\n" +
                   "     <intersection>\n" +
                   "         <intersecting>SH 13</intersecting>\n" +
                   "         <in-near>Baggs, CO</in-near>\n" +
                   "     </intersection>\n" +
                   "     <intersection>\n" +
                   "         <intersecting>I-80/US 30</intersecting>\n" +
                   "         <in-near>Creston Junction</in-near>\n" +
                   "     </intersection>\n" +
                   "     <intersection>\n" +
                   "         <intersecting>US 287</intersecting>\n" +
                   "         <in-near>Rawlins, WY</in-near>\n" +
                   "     </intersection>\n" +
                   "</intersections>\n"

)

Remember our second rule. If you want to add the new element to a node other than the root, you have to specify it. Here is an example:

Code File: RoadNew.cs

module NewRoad
open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let roadNew : Form = new Form(ShowInTaskbar = false,
                              Text = "Road System Database - New Road",
                              MaximizeBox = false, MinimizeBox = false,
                              FormBorderStyle = FormBorderStyle.FixedDialog,
                              ClientSize = new System.Drawing.Size(517, 189),
                              StartPosition = FormStartPosition.CenterScreen)

// Road Name
roadNew.Controls.Add(new Label(AutoSize = true, Text = "Road Name:",
                               Location = new System.Drawing.Point(23, 21)))
let txtRoadName = new TextBox(Width = 100, Location = new Point(96, 18))
roadNew.Controls.Add txtRoadName

// Road Type
roadNew.Controls.Add(new Label(AutoSize = true, Text = "Road Type:",
                               Location = new System.Drawing.Point(23, 51)))

let cbxRoadTypes = new ComboBox(Width = 100, Location = new Point(96, 48))
roadNew.Controls.Add cbxRoadTypes

// Distance
roadNew.Controls.Add(new Label(AutoSize = true, Text = "Distance:",
                               Location = new System.Drawing.Point(23, 82)))
let txtDistance = new TextBox(TextAlign = HorizontalAlignment.Right,
                              Width = 100, Location = new Point(96, 79))
roadNew.Controls.Add txtDistance

// Location
roadNew.Controls.Add(new Label(AutoSize = true, Text = "Location:",
                               Location = new System.Drawing.Point(23, 112)))
let txtLocation = new TextBox(Width = 400, Location = new Point(96, 109))
roadNew.Controls.Add txtLocation

// OK
let btnOK = new Button(Location = new Point(327, 147),
                       Text = "OK", DialogResult = DialogResult.OK)
roadNew.AcceptButton <- btnOK
roadNew.Controls.Add btnOK

// Cancel
let btnCancel = new Button(Location = new Point(419, 147),
                           Text = "Cancel", DialogResult = DialogResult.Cancel)
roadNew.CancelButton <- btnCancel
roadNew.Controls.Add btnCancel

let roadNewLoad e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = @"C:\Road Database\Roads.xml"

    if File.Exists strRoadsFile then
        cbxRoadTypes.Items.Clear()

        use fsRoads : FileStream = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        xdRoads.Load fsRoads
        
        let xnlRoads : XmlNodeList = xdRoads.DocumentElement.ChildNodes

        for xnRoad : XmlNode in xnlRoads do
            if cbxRoadTypes.Items.Contains(xnRoad.FirstChild.NextSibling.InnerText) = false then
                cbxRoadTypes.Items.Add xnRoad.FirstChild.NextSibling.InnerText |> ignore
        fsRoads.Close()

roadNew.Load.Add roadNewLoad

Code File: IntersectionNew.cs

module NewIntersection
open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let intersectionNew : Form = new Form(ShowInTaskbar = false,
                                      MaximizeBox = false, MinimizeBox = false,
                                      FormBorderStyle = FormBorderStyle.FixedDialog,
                                      ClientSize = new System.Drawing.Size(558, 162),
                                      StartPosition = FormStartPosition.CenterScreen,
                                      Text = "Road System Database - New Intersection")

// Existing Road
intersectionNew.Controls.Add(new Label(AutoSize = true, Text = "Existing Road:",
                                       Location = new System.Drawing.Point(22, 22)))
let cbxExistingRoads = new ComboBox(Width = 126, Location = new Point(117, 19),
                                    DropDownStyle = ComboBoxStyle.DropDownList)
intersectionNew.Controls.Add cbxExistingRoads

// Intersectin Road
intersectionNew.Controls.Add(new Label(AutoSize = true, Text = "Intersectin Road:",
                                       Location = new System.Drawing.Point(22, 54)))
let txtIntersectingRoad = new TextBox(Width = 126, Location = new Point(117, 51))
intersectionNew.Controls.Add txtIntersectingRoad

// In Or Near
intersectionNew.Controls.Add(new Label(AutoSize = true, Text = "In Or Near:",
                                       Location = new System.Drawing.Point(22, 85)))
let txtInOrNear = new TextBox(Width = 417, Location = new Point(117, 82))
intersectionNew.Controls.Add txtInOrNear

// OK
let btnOK = new Button(Location = new Point(367, 118),
                       Text = "OK", DialogResult = DialogResult.OK)
intersectionNew.AcceptButton <- btnOK
intersectionNew.Controls.Add btnOK

// Cancel
let btnCancel = new Button(Location = new Point(459, 118),
                           Text = "Cancel", DialogResult = DialogResult.Cancel)
intersectionNew.CancelButton <- btnCancel
intersectionNew.Controls.Add btnCancel

let intersectionNewLoad e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = @"C:\Road Database\Roads.xml"

    if File.Exists(strRoadsFile) then
        cbxExistingRoads.Items.Clear()

        use fsRoads : FileStream = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        xdRoads.Load fsRoads

        let xnlRoads : XmlNodeList = xdRoads.DocumentElement.ChildNodes;

        for xnRoad : XmlNode in xnlRoads do
            if cbxExistingRoads.Items.Contains(xnRoad.FirstChild.InnerText) = false then
                cbxExistingRoads.Items.Add xnRoad.FirstChild.InnerText |> ignore
        fsRoads.Close()

intersectionNew.Load.Add intersectionNewLoad

Code File: Program.cs

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

open NewRoad
open NewIntersection

let roadDatabase = new Form(ClientSize = new System.Drawing.Size(727, 678),
                            StartPosition = FormStartPosition.CenterScreen,
                            MaximizeBox = false, Text = "Road System Database")

// List View: List of Road
let lvwRoads  = new ListView(GridLines = true, View = View.Details,
                             Size = new System.Drawing.Size(702, 295),
                             FullRowSelect = true, Location = new Point(12, 14),
                             Anchor = (AnchorStyles.Top ||| AnchorStyles.Bottom ||| AnchorStyles.Left ||| AnchorStyles.Right))

let mutable colRoad = lvwRoads .Columns.Add("Road Name", 70)
colRoad <- lvwRoads.Columns.Add("Road Type", 85, HorizontalAlignment.Center)
colRoad <- lvwRoads.Columns.Add("Distance(Miles)", 85, HorizontalAlignment.Right)
colRoad <- lvwRoads.Columns.Add("Location", 445)
roadDatabase.Controls.Add lvwRoads

// List View: Intersections
let lvwIntersections  = new ListView(GridLines = true, View = View.Details,
                                     Size = new System.Drawing.Size(375, 332),
                                     FullRowSelect = true, Location = new Point(142, 325),
                                     Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Left ||| AnchorStyles.Right))

colRoad <- lvwIntersections.Columns.Add("Road", 50)
colRoad <- lvwIntersections.Columns.Add("Intersects With", 120)
colRoad <- lvwIntersections.Columns.Add("In/Near", 180)
roadDatabase.Controls.Add lvwIntersections

// Button: New Intersection
let btnNewRoad = new Button(Location = new System.Drawing.Point(535, 535),
                          Text = "New Road", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewRoad

// Button: New Road
let btnNewIntersection = new Button(Location = new System.Drawing.Point(535, 578),
                          Text = "New Intersection", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnNewIntersection

// Button: Close
let btnClose = new Button(Location = new System.Drawing.Point(535, 620),
                          Text = "Close", Size = new System.Drawing.Size(145, 36),
                          Anchor = (AnchorStyles.Bottom ||| AnchorStyles.Right))
roadDatabase.Controls.Add btnClose

let showRoads() =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = @"C:\Road Database\Roads.xml"

    if File.Exists(strRoadsFile) then
        lvwRoads.Items.Clear()
            
        use fsRoads : FileStream = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        
        xdRoads.Load fsRoads
        let xeRoad : XmlElement = xdRoads.DocumentElement
        let xnlRoads : XmlNodeList = xeRoad.ChildNodes

        for xnRoad : XmlNode in xnlRoads do
            let lviRoad = new ListViewItem(xnRoad.FirstChild.InnerText) // Road Name

            lviRoad.SubItems.Add xnRoad.FirstChild.NextSibling.InnerText |> ignore // Road Type
            lviRoad.SubItems.Add xnRoad.FirstChild.NextSibling.NextSibling.InnerText |> ignore // Distance
            lviRoad.SubItems.Add xnRoad.FirstChild.NextSibling.NextSibling.NextSibling.InnerText |> ignore // Location

            lvwRoads.Items.Add lviRoad |> ignore
        fsRoads.Close()

let roadDatabaseLoad e =
    Directory.CreateDirectory @"C:\Road Database" |> ignore
    showRoads()
roadDatabase.Load.Add roadDatabaseLoad

let lvwRoadsItemSelectionChanged(e : ListViewItemSelectionChangedEventArgs) =
    let xdRoads : XmlDocument = new XmlDocument()
    let roadSelected : string = e.Item.SubItems.[0].Text
    let strRoadsFile : string = @"C:\Road Database\Roads.xml"

    if File.Exists(strRoadsFile) then
        lvwIntersections.Items.Clear()

        use fsRoads : FileStream = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        xdRoads.Load fsRoads

        let xeRoad : XmlElement = xdRoads.DocumentElement
        let xnlRoads : XmlNodeList = xdRoads.GetElementsByTagName "road-name"

        for xnRoad : XmlNode in xnlRoads do
            if xnRoad.InnerText = roadSelected then
                let xnlIntersections : XmlNodeList = xnRoad.NextSibling.NextSibling.NextSibling.NextSibling.ChildNodes

                for i in 0 .. xnlIntersections.Count - 1 do
                    let lviIntersection : ListViewItem = new ListViewItem(roadSelected) // Selected Road
                    
                    lviIntersection.SubItems.Add xnlIntersections.[i].ChildNodes.[0].InnerText |> ignore // Intersects With
                    lviIntersection.SubItems.Add xnlIntersections.[i].ChildNodes.[1].InnerText |> ignore // In or Near

                    lvwIntersections.Items.Add lviIntersection |> ignore
        fsRoads.Close()
lvwRoads.ItemSelectionChanged.Add lvwRoadsItemSelectionChanged

let btnNewRoadClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = @"C:\Road Database\Roads.xml"

    if roadNew.ShowDialog() = DialogResult.OK then
        if File.Exists(strRoadsFile) = false then
            xdRoads.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                            "<roads />")

            use fsRoads = new FileStream(strRoadsFile, FileMode.CreateNew, FileAccess.Write)
            xdRoads.Save fsRoads
            fsRoads.Close()

        use fsRoads = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
        xdRoads.Load fsRoads
        fsRoads.Close()
        
        use fsRoads = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
        
        let xeRoad : XmlElement = xdRoads.CreateElement "road"
        xeRoad.InnerXml <- "<road-name>" + NewRoad.txtRoadName.Text + "</road-name>" +
                           "<road-type>" + NewRoad.cbxRoadTypes.Text + "</road-type>" +
                           "<distance>" + NewRoad.txtDistance.Text + "</distance>" +
                           "<location>" + NewRoad.txtLocation.Text + "</location>" +
                           "<intersections />"
        let xnRoad = xdRoads.DocumentElement.AppendChild xeRoad
        xdRoads.Save fsRoads
        fsRoads.Close()

        NewRoad.txtRoadName.Text <- ""
        NewRoad.cbxRoadTypes.Text <- ""
        NewRoad.txtDistance.Text <- ""
        NewRoad.txtLocation.Text <- ""

    showRoads()

btnNewRoad.Click.Add btnNewRoadClick

let btnNewIntersectionClick e =
    let xdRoads : XmlDocument = new XmlDocument()
    let strRoadsFile : string = @"C:\Road Database\Roads.xml"

    if intersectionNew.ShowDialog() = DialogResult.OK then
        if String.IsNullOrEmpty(NewIntersection.cbxExistingRoads.Text) then
            MessageBox.Show("You must select the road whose intersection(s) you want to specify.",
                                "Road System Database", MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore
        elif String.IsNullOrEmpty(NewIntersection.txtIntersectingRoad.Text) then
            MessageBox.Show("You must enter the name of a road that intersects with the selected road.",
                            "Road System Database", MessageBoxButtons.OK, MessageBoxIcon.Information) |> ignore
        else
            if File.Exists(strRoadsFile) then
                use fsRoads : FileStream = new FileStream(strRoadsFile, FileMode.Open, FileAccess.Read)
                xdRoads.Load fsRoads
                fsRoads.Close()
                
                let xnlRoads : XmlNodeList = xdRoads.GetElementsByTagName "road-name"

                use fsRoads : FileStream = new FileStream(strRoadsFile, FileMode.OpenOrCreate, FileAccess.Write)
                
                for xnIntersection : XmlNode in xnlRoads do
                    if xnIntersection.InnerText = NewIntersection.cbxExistingRoads.Text then
                        let xeIntersection : XmlElement = xdRoads.CreateElement "intersection"

                        xeIntersection.InnerXml <- "<intersecting>" + NewIntersection.txtIntersectingRoad.Text + "</intersecting>" +
                                                   "<in-near>" + NewIntersection.txtInOrNear.Text + "</in-near>";
                        let xnCreated = xnIntersection.NextSibling.NextSibling.NextSibling.NextSibling.AppendChild xeIntersection
                        xdRoads.Save fsRoads

                        NewIntersection.txtIntersectingRoad.Text <- ""
                        NewIntersection.txtInOrNear.Text <- ""
                fsRoads.Close()

    showRoads()
btnNewIntersection.Click.Add btnNewIntersectionClick

let btnCloseClick e = roadDatabase.Close()
btnClose.Click.Add btnCloseClick

[<EntryPoint>]
let main argv = 
    Application.Run roadDatabase
    0

An examples of running the program would produce:

Locating an Element Using a Tag Name

Locating an Element Using a Tag Name

Locating an Element Using a Tag Name

Locating an Element Using a Tag Name

Adding an Element With Value

Consider the following XML file named videos.xml:

<?xml version="1.0" encoding="utf-8" ?>
<videos>
  <title>The Distinguished Gentleman</title>
</videos>

If you want the element to have a value, the XmlDocument class provides the CreateTextNode() method. This method returns an XmlText value. The signature of this method is:

abstract CreateTextNode : 
        text:string -> XmlText  
override CreateTextNode : 
        text:string -> XmlText

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. Calling this method on the LastChild node of the one that called the AppendChild() would specify the value of the new node. Here is an example:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Start XML File", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideoCollection : XmlDocument = new XmlDocument()

    if File.Exists(strFileName) = false then
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
        xdVideoCollection.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                  "<videos></videos>")
        xdVideoCollection.Save(fsVideo)
        fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
    xdVideoCollection.Load fsVideo
    fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
    let xeRoot : XmlElement = xdVideoCollection.DocumentElement
    let xeVideo : XmlElement = xdVideoCollection.CreateElement "title"
    
    let txtvideo : XmlText = xdVideoCollection.CreateTextNode("Basic Instinct")

    xeRoot.AppendChild xeVideo |> ignore
    xeRoot.LastChild.AppendChild txtvideo |> ignore
    xdVideoCollection.Save fsVideo

    fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<videos>
  <title>The Distinguished Gentleman</title>
  <title>Basic Instinct</title>
</videos>

The combination of calls to XmlDocument.CreateElement() and XmlDocument.CreateTextNode() allow you to create a new element that has a value.

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:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Start XML File", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideoCollection : XmlDocument = new XmlDocument()

    if File.Exists(strFileName) = false then
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
        xdVideoCollection.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                  "<videos></videos>")
        xdVideoCollection.Save(fsVideo)
        fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
    xdVideoCollection.Load fsVideo
    fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
    let xeRoot : XmlElement = xdVideoCollection.DocumentElement
    
    let xeVideo : XmlElement = xdVideoCollection.CreateElement "video"
    
    xeRoot.AppendChild xeVideo |> ignore
    xdVideoCollection.Save fsVideo

    fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

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 don't 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:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Start XML File", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideoCollection : XmlDocument = new XmlDocument()

    if File.Exists(strFileName) = false then
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
        xdVideoCollection.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                  "<videos></videos>")
        xdVideoCollection.Save(fsVideo)
        fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
    xdVideoCollection.Load fsVideo
    fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
    let xeRoot : XmlElement = xdVideoCollection.DocumentElement

    let mutable xeVideo : XmlElement = xdVideoCollection.CreateElement "video"
    xeRoot.AppendChild xeVideo |> ignore

    xeVideo <- xdVideoCollection.CreateElement "title"

    let txtvideo : XmlText = xdVideoCollection.CreateTextNode("Her Alibi")

    xeRoot.LastChild.AppendChild xeVideo |> ignore
    xeRoot.LastChild.LastChild.AppendChild txtvideo |> ignore

    xdVideoCollection.Save fsVideo

    fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

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 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 would be done as follows:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Start XML File", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideoCollection : XmlDocument = new XmlDocument()

    if File.Exists(strFileName) = false then
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
        xdVideoCollection.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                  "<videos></videos>")
        xdVideoCollection.Save(fsVideo)
        fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
    xdVideoCollection.Load fsVideo
    fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
    let xeRoot : XmlElement = xdVideoCollection.DocumentElement

    let mutable xeVideo : XmlElement = xdVideoCollection.CreateElement "video"
    xeRoot.AppendChild xeVideo |> ignore
    xeVideo <- xdVideoCollection.CreateElement "title"
    let txtvideo : XmlText = xdVideoCollection.CreateTextNode("The Day After Tomorrow")
    xeRoot.LastChild.AppendChild xeVideo |> ignore
    xeRoot.LastChild.LastChild.AppendChild txtvideo |> ignore
    
    xeVideo <- xdVideoCollection.CreateElement "director"
    let txtvideo : XmlText = xdVideoCollection.CreateTextNode("Roland Emmerich")
    xeRoot.LastChild.AppendChild xeVideo |> ignore
    xeRoot.LastChild.LastChild.AppendChild txtvideo |> ignore
    
    xeVideo <- xdVideoCollection.CreateElement "length"
    let txtvideo : XmlText = xdVideoCollection.CreateTextNode("124 Minutes")
    xeRoot.LastChild.AppendChild xeVideo |> ignore
    xeRoot.LastChild.LastChild.AppendChild txtvideo |> ignore
    
    xeVideo <- xdVideoCollection.CreateElement "format"
    let txtvideo : XmlText = xdVideoCollection.CreateTextNode("DVD")
    xeRoot.LastChild.AppendChild xeVideo |> ignore
    xeRoot.LastChild.LastChild.AppendChild txtvideo |> ignore
    
    xeVideo <- xdVideoCollection.CreateElement "rating"
    let txtvideo : XmlText = xdVideoCollection.CreateTextNode("PG-13")
    xeRoot.LastChild.AppendChild xeVideo |> ignore
    xeRoot.LastChild.LastChild.AppendChild txtvideo |> ignore

    xdVideoCollection.Save fsVideo

    fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

 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.

Inserting an Element

 

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 XmlElement class is equipped with a method named PrependChild. Its signature is:

abstract PrependChild : 
        newChild:XmlNode -> XmlNode  
override PrependChild : 
        newChild:XmlNode -> XmlNode

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:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Create XML Element",
			     Location = new Point(12, 12), Width = 150)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos: XmlDocument = new XmlDocument()

    if File.Exists strFileName = false then
        xdVideos.LoadXml("<?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>")
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
        xdVideos.Save fsVideo
        fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
    xdVideos.Load fsVideo
    fsVideo.Close()

    use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
    // Create a new XML element
    let xeVideo : XmlElement = 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
    xdVideos.DocumentElement.PrependChild xeVideo |> ignore
    // Save the file
    xdVideos.Save fsVideo

    fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

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>

Adding an Element as a Last Child

Once again, consider 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>
    </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>
    <video>
	<title>Other People's Money</title>
	<director>Alan Brunstein</director>
	<length>114 Minutes</length>
	<format>VHS</format>
	<rating>PG-13</rating>
    </video>
</videos>

Imagine you want to add a list of actors of the Her Alibi video. The first action to take is to locate the video, which you can do by calling the XmlDocument.GetElementsByTagName() method applied to a collection of nodes whose names are video. From this list of nodes, you can look for the node whose value is "Her Alibi". Once you have found this element, get a reference to its parent. Then add the new node as a child of its parent. This can be done as follows, using only the file name:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Document", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        xdVideos.Load strFileName

        // Create a list of nodes whose name is Title
        let xnlTitles : XmlNodeList = xdVideos.GetElementsByTagName "title"
    
        // use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
        xdVideos.Load strFileName

        // Now you can check each node of the list
        for node in xnlTitles do
            if node.InnerText = "Her Alibi" then
                // Create an element named Actors
                let xeVideo : XmlElement = xdVideos.CreateElement "actors"
                let xnParent : XmlNode = node.ParentNode
                // Add a new element named Actors to it
                xnParent.AppendChild xeVideo |> ignore
                xdVideos.Save strFileName

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

Here is an example that uses a file stream:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Document", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlTitles : XmlNodeList = xdVideos.GetElementsByTagName "title"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)

        // Now you can check each node of the list
        for node in xnlTitles do
            if node.InnerText = "Her Alibi" then
                // Create an element named Actors
                let xeVideo : XmlElement = xdVideos.CreateElement "actors"
                let xnParent : XmlNode = node.ParentNode
                // Add a new element named Actors to it
                xnParent.AppendChild xeVideo |> ignore
                xdVideos.Save fsVideo

        fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<videos>
  . . .
  <video>
    <title>Her Alibi</title>
    <director>Bruce Beresford</director>
    <length>94 Minutes</length>
    <format>DVD</format>
    <rating>PG-13</rating>
    <actors />
  </video>
  . . .
</videos>

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:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Document", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlTitles : XmlNodeList = xdVideos.GetElementsByTagName "title"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)

        // Now you can check each node of the list
        for node in xnlTitles do
            if node.InnerText.ToLower().Contains("distinguished gentleman") then
                // Create an element named Category
                let xeVideo : XmlElement = xdVideos.CreateElement "category"
                // Create the text of the new element
                let txtCatetory : XmlText = xdVideos.CreateTextNode "Comedy"
                // Get a reference to the parent of the node we have found
                let xeParent : XmlNode = node.ParentNode
                // Add the new element to the node we found
                xeParent.AppendChild xeVideo |> ignore
                // Specify the text of the new node
                xeParent.LastChild.AppendChild txtCatetory |> ignore
                // Save the file
                xdVideos.Save fsVideo

        fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

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:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Document", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlTitles : XmlNodeList = xdVideos.GetElementsByTagName "title"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)

        // Now you can check each node of the list
        for node in xnlTitles do
            // 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.ToLower().Contains("day after tomorrow") then
                // Create an element named Actors
                let mutable xeVideo : XmlElement = xdVideos.CreateElement "actors"
                // Get a reference to the parent of the node we have found
                let xnVideo : XmlNode = node.ParentNode
                // Add the new element to the node we found
                xnVideo.AppendChild xeVideo |> ignore

                // Create an element as a child of the new element
                // Specify its name as Actor
                xeVideo <- xdVideos.CreateElement "actor"
                // Create the text of the new element
                let mutable txtActor : XmlText = xdVideos.CreateTextNode "Dennis Quaid"
                // Add the new Actor element to the Actors node
                xnVideo.LastChild.AppendChild xeVideo |> ignore
                // Specify the text of the new node
                xnVideo.LastChild.LastChild.AppendChild txtActor |> ignore

                // In the same way, add the other Actor nodes
                xeVideo  <- xdVideos.CreateElement "actor"
                txtActor <- xdVideos.CreateTextNode "Jake Gyllenhaal"
                xnVideo.LastChild.AppendChild xeVideo |> ignore
                xnVideo.LastChild.LastChild.AppendChild txtActor |> ignore

                xeVideo  <- xdVideos.CreateElement "actor"
                txtActor <- xdVideos.CreateTextNode "Emmy Rossum"
                xnVideo.LastChild.AppendChild xeVideo |> ignore
                xnVideo.LastChild.LastChild.AppendChild txtActor |> ignore

                xeVideo  <- xdVideos.CreateElement "actor"
                txtActor <- xdVideos.CreateTextNode "Dash Mihok"
                xnVideo.LastChild.AppendChild xeVideo |> ignore
                xnVideo.LastChild.LastChild.AppendChild txtActor |> ignore

                // Save the file
                xdVideos.Save fsVideo

        fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

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>

Consider the following XML 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>
    <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>

You can insert one or more elements as children of an existing node after locating that node. Here is an example:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Document", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlTitles : XmlNodeList = xdVideos.GetElementsByTagName "title"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)

        // Now you can check each node of the list
        for xnTitle in xnlTitles do
            // 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 xnTitle.InnerText.ToLower().Contains("her alibi") then
                // Get a reference to the video node that is 
                // the parent of the video titled Her Alibi
                let xnVideo : XmlNode = xnTitle.ParentNode

                // Create a list of the child nodes of the Her alibi video
                let xnlActors : XmlNodeList = xnVideo.ChildNodes

                // Visit each item of the collection
                // looking for an element named Actors
                for xnActor in xnlActors do
                    // If you find an element named Actors
                    if xnActor.Name = "actors" then
                        // Create a new element named Actor
                        // Specify its name as Actor
                        let mutable xeVideo : XmlElement = xdVideos.CreateElement "actor"
                        // Create the text of the new element
                        let mutable txtActor : XmlText = xdVideos.CreateTextNode "Tom Selleck"
                        // Add the new Actor element to the Actors node
                        xnVideo.LastChild.AppendChild xeVideo |> ignore
                        // Specify the text of the new node
                        xnVideo.LastChild.LastChild.AppendChild txtActor |> ignore

                        // Add other Actor nodes
                        xeVideo  <- xdVideos.CreateElement "actor"
                        txtActor <- xdVideos.CreateTextNode "Paulina Porizkova"
                        xnVideo.LastChild.AppendChild xeVideo |> ignore
                        xnVideo.LastChild.LastChild.AppendChild txtActor |> ignore

                        xeVideo  <- xdVideos.CreateElement "actor"
                        txtActor <- xdVideos.CreateTextNode "William Daniels"
                        xnVideo.LastChild.AppendChild xeVideo |> ignore
                        xnVideo.LastChild.LastChild.AppendChild txtActor |> ignore

                // Save the file
                xdVideos.Save fsVideo

        fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

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>

Inserting an Element Referencing 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 provides the InsertBefore() method. Its signatur is:

abstract InsertBefore : 
        newChild:XmlNode * 
        refChild:XmlNode -> XmlNode  
override InsertBefore : 
        newChild:XmlNode * 
        refChild:XmlNode -> XmlNode

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:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDocument = new Button(Text = "Document", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDocument

let btnDocumentClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlVideos : XmlNodeList = xdVideos.GetElementsByTagName "video"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)

        // Now you can check each node of the list
        for xnTitle in xnlVideos do
            // Within a video, create a list of its children
            let xnlChildren : XmlNodeList = xnTitle.ChildNodes

            // Visit each child node
            for xnChild in xnlChildren do
                // If the child node is (a xnChildector and its name is) Adrian Lyne
                if xnChild.InnerText = "Adrian Lyne" then
                    // Create an element named Category
                    let xeVideo : XmlElement = xdVideos.CreateElement "category"
                    // Specify the text of the new element
                    xeVideo.InnerText <- "Drama"

                    // Insert the new node below the Adrian Lyne node xnChildector
                    xnTitle.InsertAfter(xeVideo, xnChild) |> ignore

                    // Save the file
                    xdVideos.Save fsVideo

        fsVideo.Close()

btnDocument.Click.Add btnDocumentClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

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.

If you want to new node to be positioned after an existing child node, you can call the XmlNode.InsertAfter() method. Its signatur is:

abstract InsertAfter : 
        newChild:XmlNode * 
        refChild:XmlNode -> XmlNode  
override InsertAfter : 
        newChild:XmlNode * 
        refChild:XmlNode -> XmlNode

Updating an Element

The .NET Framework implementation of XML provides various options to change the aspect, structure, or value(s), of an element. For example, you can use the same logic used in collection classes. This consists of locating a node and simply changing its value(s). Here is an example:

<?xml version="1.0" encoding="utf-8"?>
<videos>
  <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>
----------------------------------------------------------------
open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnUpdate = new Button(Text = "Update", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnUpdate

let btnUpdateClick _ =
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlVideos : XmlNodeList = xdVideos.GetElementsByTagName "title"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)

        try
            for xnVideo in xnlVideos do
                if xnVideo.InnerText.ToLower().Contains("day after tomorrow") then
                        xnVideo.ParentNode.InnerXml <- "<title>Day After Tomorrow(The)</title>" +
                                                       "<director>Roma Mafia Emmerich</director>" +
                                                       "<year>20104</year>" +
                                                       "<length>2h 4 Minutes</length>" +
                                                       "<format>Blu-Ray</format>" +
                                                       "<rating>PG13</rating>"

                        xdVideos.Save fsVideo
        with
        | :? InvalidOperationException as ioe -> () 

        fsVideo.Close()

btnUpdate.Click.Add btnUpdateClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0
----------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<videos>
  <video>
    <title>Her Alibi</title>
    <director>Bruce Beresford</director>
    <length>94 Minutes</length>
    <format>DVD</format>
    <rating>PG-13</rating>
  </video>
  <video>
    <title>Day After Tomorrow(The)</title>
    <director>Roland Emmerich</director>
    <year>2004</year>
    <length>124</length>
    <format>DVD</format>
    <rating>PG-13</rating>
  </video>
</videos>

On the other hand, the XmlNode class is equipped with a method named ReplaceChild. Its signatur is:

abstract ReplaceChild : 
        newChild:XmlNode * 
        oldChild:XmlNode -> XmlNode  
override ReplaceChild : 
        newChild:XmlNode * 
        oldChild:XmlNode -> XmlNode

To use this method, first locate an element and get its reference. Then change the values or child nodes you want, and finally replace the original value with the new version. In reality, and as its name implies, it is not the primary purpose of this method to edit or update an element. The role of this method is to use one node in place of another.

Deleting Elements

 

Deleting an Element

If you have a node you don't want or don't need anymore in the file, you can delete it. To delete a node, the XmlNode class provides the RemoveChild() method. Its signatur is:

abstract RemoveChild : 
        oldChild:XmlNode -> XmlNode  
override RemoveChild : 
        oldChild:XmlNode -> XmlNode

This method takes as argument the node to delete. If the node exists, it would be deleted and the method would return the node that was deleted. If the node does not exist, nothing would happen. To effectively use this method, you should first locate the particular node you want to delete. You can look for it using any of the logics we have applied so far. Once you find the node, you can then delete it. Imagine you want to delete a node whose name is Director and whose value is Bruce Beresford. Here is an example of calling this method to perform the operation:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnUpdate = new Button(Text = "Delete Node", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnUpdate

let btnDeleteClick _ =
    let mutable xnNewVideo = null
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlVideos : XmlNodeList = xdVideos.GetElementsByTagName "video"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)

        // visit each video
        for xnVideo in xnlVideos do
            // Within a video, get a list of its children
            let xnlChildren : XmlNodeList = xnVideo.ChildNodes

            // Visit each child node
            for xnChild in xnlChildren do
                // If the child node is Bruce Beresford
                if xnChild.InnerText = "Bruce Beresford" then
                    xnVideo.RemoveChild xnChild |> ignore
       
                    xdVideos.Save fsVideo

        fsVideo.Close()

btnDelete.Click.Add btnDeleteClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

Clearing an Element of its Children

To delete all child nodes of a node, you can call the XmlNode.RemoveAll() method. Its signatur is:

abstract RemoveAll : unit -> unit  
override RemoveAll : unit -> unit

When called, this method will remove all child nodes, if any, of their parent node. Here is an example of calling it:

open System
open System.IO
open System.Xml
open System.Drawing
open System.Windows.Forms

let exercise = new Form(MaximizeBox = false, Text = "Video Collection",
                        ClientSize = new System.Drawing.Size(225, 120),
                        StartPosition = FormStartPosition.CenterScreen)

let btnDeleteAll = new Button(Text = "Delete All Videos", Location = new Point(12, 12), Width = 100)
exercise.Controls.Add btnDeleteAll

let btnDeleteAllClick _ =
    let mutable xnNewVideo = null
    let strFileName = "..\..\Videos.xml"
    let xdVideos : XmlDocument = new XmlDocument()

    if File.Exists strFileName then
        use fsVideo = new FileStream(strFileName, FileMode.Open, FileAccess.Read)
        xdVideos.Load strFileName
        fsVideo.Close()

        // Create a list of nodes whose name is Title
        let xnlVideos : XmlNodeList = xdVideos.GetElementsByTagName "video"
    
        use fsVideo = new FileStream(strFileName, FileMode.Create, FileAccess.Write)
        
        // Clear the XML document
        xdVideos.DocumentElement.RemoveAll()
        xdVideos.Save fsVideo 

        fsVideo.Close()

btnDeleteAll.Click.Add btnDeleteAllClick

[<EntryPoint>]
let main argv = 
    Application.Run exercise
    0

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<videos>
</videos>

Home Copyright © 2015 FunctionX Home