In this post I’m going to help the people who have asked me about the XmlDataSource’s Save method. I got some questions regarding this method and I think other cold be interested in this post.
When you use the XmlDataSource control, you can use the DataFile property to specify which xml-file the data source control should use. The data source control will use the specified xml-file and load it into an internal XmlDocument (You can get this document by using the XmlDataSource’s GetXmlDocument method). When the Save button of the XmlDataSource control is called, the internal XMLDocument will be saved to the file specified to the DataFile property (The file will be overwritten).
With the XmlDataSource’s GetXmlDocument method you can get the instance of the loaded XmlDocuemnt, and by using it, you could change, add, remove and update a node to the specified DataFile.
The following example will use a TreeView to display the nodes located within an XML file. The example also has a “add new node” button that will display a hidden form for adding a node to the selected node in the tree:
<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Import Namespace="System.Xml" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
protected void addNewNode_Click(object sender, EventArgs e)
{
addNodePlaceHolder.Visible = true;
TreeNode node = TreeView1.SelectedNode;
parentNodeName.Text = node.Text;
addNewNode.Enabled = false;
}
protected void cancelButton_Click(object sender, EventArgs e)
{
addNodePlaceHolder.Visible = false;
}
protected void saveButton_Click(object sender, EventArgs e)
{
XmlDocument myXml = XmlDataSource1.GetXmlDocument();
XmlNode selectedNode = myXml.SelectSingleNode(TreeView1.SelectedNode.DataPath);
selectedNode.AppendChild(this.CreateNewNode(myXml, nodeName.Text, path.Text));
XmlDataSource1.Save();
addNodePlaceHolder.Visible = false;
TreeView1.DataBind();
}
private XmlElement CreateNewNode(XmlDocument myXml, string name, string url)
{
XmlElement newNode = myXml.CreateElement("node");
XmlAttribute titleAttribute = myXml.CreateAttribute("title");
titleAttribute.Value = name;
XmlAttribute urlAttribute = myXml.CreateAttribute("url");
urlAttribute.Value = url;
newNode.Attributes.Append(titleAttribute);
newNode.Attributes.Append(urlAttribute);
return newNode;
}
protected void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
{
addNewNode.Enabled = true;
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder ID="addNodePlaceHolder" runat="server" visible="false">
Add new node to node: <asp:Label ID="parentNodeName" runat="server"></asp:Label><br />
Name: <asp:TextBox ID="nodeName" runat="server"></asp:TextBox><br />
Path: <asp:TextBox ID="path" runat="server"></asp:TextBox><br />
<asp:Button runat="server" ID="saveButton" Text="Add" OnClick="saveButton_Click" />
<asp:Button runat="server" ID="cancelButton" Text="Cancel" OnClick="cancelButton_Click" />
</asp:PlaceHolder>
<br /> <br />
<asp:TreeView
ID="TreeView1"
AutoGenerateDataBindings=false
DataSourceID="XmlDataSource1"
Runat="server"
OnSelectedNodeChanged="TreeView1_SelectedNodeChanged">
<SelectedNodeStyle BorderStyle=Dotted BackColor=GrayText Font-Bold=true />
<DataBindings>
<asp:TreeNodeBinding DataMember="Node" TextField="title"/>
</DataBindings>
</asp:TreeView>
<asp:XmlDataSource DataFile="~/nodes.xml" ID="XmlDataSource1" runat="server"/>
<asp:Button Enabled=false ID="addNewNode" runat="server" Text="Add new node" OnClick="addNewNode_Click" />
</div>
</form>
</body>
</html>
nodes.xml
<?xml version="1.0" encoding="utf-8"?>
<node url="default.aspx" title="Home">
<node url="url1" title="Welcome"/>
<node url="url2" title="About" />
</node>
I think you can see what the code in the example above does by only looking at it, so I decide to only explain the code within the saveButton_Click method:
protected void saveButton_Click(object sender, EventArgs e)
{
XmlDocument myXml = XmlDataSource1.GetXmlDocument();
XmlNode selectedNode = myXml.SelectSingleNode(TreeView1.SelectedNode.DataPath);
selectedNode.AppendChild(this.CreateNewNode(myXml, nodeName.Text, path.Text));
XmlDataSource1.Save();
addNodePlaceHolder.Visible = false;
TreeView1.DataBind();
}
The code above will use the XmlDataSource control’s GetXmlDocument, to get an instance of the loaded xml file specified for the data source control. By using the TreeView control’s SelectedNode’s DataPath (The DataPath property will return the XPath of the selected node) property, the selected node could be find within the XmlDocument by using the XmlDocument’s SelectSingleNode method. When the node is found, a new node will be created and added to the selected node. When this is done the XmlDataSource control’s Save method will be called to save the new XMLDocument. To see the new added node, the TreeView’s DataBind method is called to “refresh” the TreeView.
The rest of this post will contain code examples of how you can remove and update a selected node.
The following example will remove the selected node:
XmlDocument myXml = XmlDataSource1.GetXmlDocument();
XmlNode selectedNode = myXml.SelectSingleNode(TreeView1.SelectedNode.DataPath);
if (selectedNode.ParentNode == null)
selectedNode.RemoveAll();
else
selectedNode.ParentNode.RemoveChild(parentNode);
XmlDataSource1.Save();
TreeView1.DataBind();
Note: If the selected node is the root node of the XmlDocument, the ParentNode property used in the example above will be null.
The following code will update the selected row:
XmlDocument myXml = XmlDataSource1.GetXmlDocument();
XmlNode selectedNode = selectedNode.SelectSingleNode(TreeView1.SelectedNode.DataPath);
selectedNode.Attributes["title"].Value = title;
selectedNode.Atrtibutes["url"].value = path;
XmlDataSource1.Save();
TreeView1.DataBind();