<parent> <child id=”123”>text here</child> </parent> |
如果用DOM加载以上文档,它将在内存中创建的树型结构如下图:
DOM的关键在于它允许直接更新内存中的树型结构,而不必重定向到其他输出,因此,添加、更新或删除结构中信息的操作效率更高。而作为程序员的我们重要的是要了解DOM所提供的编程接口以实现对XML文档进行操作,事实上,.NET Framework定义了一组类用于反映DOM的体系结构,下面来看一下.NET DOM的继承结构:
在上图中所有弧角矩形中所包含的类描述了所有可能在XML文档中出现的节点类型,而操作XML文档不外乎是操作其中的节点,这些类又都是从XmlNode类派生而来,所以我们今天的主题是讨论XmlNode类和它的子类XmlDocument,下面对这些类做简单的介绍:
XmlNode类:
该类是DOM中所有其他节点的抽象基类,它定义所有在更低级的类中继承或重写的成员。它表示XML文档中的单一节点,它提供了用于导航DOM树型结构的基本方法和属性,使用XmlNodeType枚举器可以枚举其下的所有节点类型。以下介绍该类的部分属性和方法:
属性:
[C#]
public virtual bool HasChildNodes {get;} 获取一个值,该值指示当前节点是否有任何子节点
public virtual XmlNodeList ChildNodes {get;} 获取当前节点的所有子节点
public virtual XmlNode FirstChild {get;} 获取当前节点的第一个子级
public virtual XmlNode LastChild {get;} 获取当前节点的最后一个子级
public virtual XmlNode ParentNode {get;} 获取当前节点的父级
public virtual XmlNode NextSibling {get;} 获取当前节点的下一个兄弟节点
public virtual XmlNode PreviousSibling {get;} 获取当前节点的上一个兄弟节点
public virtual string InnerText {get; set;} 获取或设置当前节点及其所有子节点的文本内容的串联值
public virtual string InnerXml {get; set;} 获取或设置仅代表当前节点的子节点的标记
public virtual string OuterXml {get;} 获取表示当前节点及其所有子节点的标记
方法:
public XmlNodeList SelectNodes(string); 选择文档中匹配 XPath 表达式的节点列表
public XmlNode SelectSingleNode(string); 选择文档中匹配 XPath 表达式的第一个 XmlNode
public virtual XmlNode AppendChild(XmlNode newChild) 将指定的节点添加到该节点的子节点列表的末尾
public virtual XmlNode PrependChild(XmlNode newChild) 将指定的节点添加到该节点的子节点列表的开头
public virtual XmlNode RemoveChild(XmlNode oldChild) 移除指定的子节点
public virtual XmlNode ReplaceChild(XmlNode newChild,XmlNode oldChild) 用 newChild 节点替换子节点 oldChild
XmlNodeList类:
该类表示XmlNode的有序集合,它有以下常用成员:
Count——以整数形式返回XmlNodeList中的节点数
ItemOf——搜索在指定索引处的节点
GetEnumerator()——提供迭代遍历节点列表的foreach样式
Item()——返回参数指定的索引处的节点
XmlDocument类:
XmlDocument类是XML文档的.NET表示形式,它代表了内存中树型结构的文档节点(所有的节点都在文档节点下),XmlDocument类包含所有的CreateXXX()方法,这些方法允许创建所有派生自XmlNode的类型的节点,通常将该类与XmlNode类一起使用以完成对文档的操作,该类有一个Load()方法用于加载XML文档,该方法的一个重载版本允许从XmlTextReader加载文档,这给我们带来的好处是在操作较大的文档时我们可以先使用XmlTextReader过滤不相关的文档部分,这样即解决了DOM所带来的资源损耗问题又可以保留DOM对文档操控的便利性,该类的Save()方法用于保存文档。
接下来用一个简单的例子来说明在C#中如何实现DOM,照旧看代码前先看下运行效果图:
LoadXML按纽用于加载XML文档,LoadXMLReader按纽使用XmlTextReader加载文档,SaveXML按纽保存文档,SaveXMLWriter按纽将文档保存到XmlTextWriter中,Add Product按纽添加节点,Replace Product按纽替换节点,Change Order按纽修改文档,Remove Product Info按纽移除节点。
DomOperation类封装了所有按纽功能的实现,代码如下:
namespace DOMSamples
{
using System;
using System.Xml;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
/// <summary>
/// DomOperation 提供对Xml文件操作的类
/// </summary>
/// <remarks>
/// 该类用于提供对XML文件进行一般的操作,如(添加,删除,替换节点,加载,保存文件)等,该类内部实现采用DOM技术。
/// </remarks>
public class DomOperation : IDisposable
{
private string _xmlPath;
private XmlDocument xmlDoc;
#region DomOperation 构造器
/// <summary>
/// 默认构造器,对该类成员进行默认赋值
/// </summary>
public DomOperation()
{
this._xmlPath = string.Empty;
this.xmlDoc = null;
}
/// <summary>
/// 带参构造器,对该类成员进行初始赋值
/// </summary>
/// <param name="xmlPath">xml文件路径</param>
public DomOperation(string xmlPath)
{
this._xmlPath = xmlPath;
this.xmlDoc = null;
}
#endregion
#region DomOperation 资源释放方法
/// <summary>
/// 清理该对象所有正在使用的资源
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 释放该对象的实例变量
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!disposing)
return;
if (this._xmlPath != null)
{
this._xmlPath = null;
}
if (this.xmlDoc != null)
{
this.xmlDoc = null;
}
}
#endregion
#region DomOperation 属性
/// <summary>
/// 获取或设置Xml文件的路径
/// </summary>
public string xmlPath
{
get
{
return _xmlPath;
}
set
{
this._xmlPath = value;
}
}
#endregion
/// <summary>
/// 加载XML文件
/// </summary>
/// <remarks>
/// 该方法使用XML文件的路径加载XML文件并返回整个XML文件的内容
/// </remarks>
/// <returns>整个XML文件的内容</returns>
public string Load()
{
xmlDoc = new XmlDocument();
try
{
xmlDoc.Load(this._xmlPath);
}
catch(XmlException xmlExp)
{
throw new XmlException(xmlExp.ToString());
}
return xmlDoc.OuterXml;
}
/// <summary>
/// 加载XML文件
/// </summary>
/// <remarks>
/// 该方法使用XmlReader在XML文档中定位并加载XML文件最后返回XML文件的内容
/// </remarks>
/// <param name="nodeType">将要定位的节点类型</param>
/// <param name="localName">将要定位的节点名称</param>
/// <returns>XML文件的内容</returns>
public string LoadByXmlReader(XmlNodeType nodeType, string localName)
{
string xmlStr = string.Empty;
XmlTextReader xmlTxtRd = new XmlTextReader(this._xmlPath);
xmlDoc = new XmlDocument();
try
{
// 在文档中定位
while(xmlTxtRd.Read())
{
if (xmlTxtRd.NodeType == nodeType)
if(xmlTxtRd.LocalName == localName)
break;
}
xmlDoc.Load(xmlTxtRd);
xmlTxtRd.Close();
xmlStr += "===== OuterXml =====";
xmlStr += System.Environment.NewLine;
xmlStr += xmlDoc.FirstChild.OuterXml;
xmlStr += System.Environment.NewLine;
xmlStr += System.Environment.NewLine;
xmlStr += "===== InnerXml =====";
xmlStr += System.Environment.NewLine;
xmlStr += xmlDoc.FirstChild.InnerXml;
xmlStr += System.Environment.NewLine;
xmlStr += System.Environment.NewLine;
xmlStr += "===== InnerText =====";
xmlStr += System.Environment.NewLine;
xmlStr += xmlDoc.FirstChild.InnerText;
xmlStr += System.Environment.NewLine;
xmlStr += System.Environment.NewLine;
xmlStr += "===== Value =====";
xmlStr += System.Environment.NewLine;
xmlStr += xmlDoc.FirstChild.ChildNodes[0].ChildNodes[0].Value + " " +
xmlDoc.FirstChild.ChildNodes[1].ChildNodes[0].Value + " " +
xmlDoc.FirstChild.ChildNodes[2].ChildNodes[0].Value;
xmlStr += System.Environment.NewLine;
xmlStr += System.Environment.NewLine;
}
catch(XmlException xmlExp)
{
throw new XmlException(xmlExp.ToString());
}
finally
{
if (xmlTxtRd != null && xmlTxtRd.ReadState != ReadState.Closed)
xmlTxtRd.Close();
}
return xmlStr;
}
/// <summary>
/// 保存XML文件
/// </summary>
/// <remarks>
/// 该方法将传入的XML文本保存在传入的路径中最后返回XML文件的内容
/// </remarks>
/// <param name="xmlText">XML文本</param>
/// <param name="savePath">保存路径</param>
/// <returns>XML文件的内容</returns>
public string Save(string xmlText, string savePath)
{
xmlDoc = new XmlDocument();
try
{
xmlDoc.LoadXml(xmlText);
xmlDoc.Save(savePath);
xmlDoc.Load(savePath);
}
catch(XmlException xmlExp)
{
throw new XmlException(xmlExp.ToString());
}
return xmlDoc.OuterXml;
}
/// <summary>
/// 保存XML文件
/// </summary>
/// <remarks>
/// 该方法将传入的XML文本保存在XmlTextWriter编写器中并使用传入的路径构造该编写器最后返回XML文件的内容
/// </remarks>
/// <param name="xmlText">XML文本</param>
/// <param name="savePath">保存路径</param>
/// <returns>XML文件的内容</returns>
public string SaveByXmlWriter(string xmlText, string savePath)
{
XmlTextWriter xmlTxtWt = new XmlTextWriter(savePath,Encoding.Unicode);
xmlDoc = new XmlDocument();
try
{
xmlDoc.LoadXml(xmlText);
xmlDoc.Save(xmlTxtWt);
xmlTxtWt.Close();
xmlDoc.Load(savePath);
}
catch(XmlException xmlExp)
{
throw new XmlException(xmlExp.ToString());
}
finally
{
if (xmlTxtWt != null && xmlTxtWt.WriteState != WriteState.Closed)
xmlTxtWt.Close();
}
return xmlDoc.OuterXml;
}
/// <summary>
/// 添加子节点
/// </summary>
/// <remarks>
/// 该方法利用传入的父节点路径选择该节点并将传入的XML文档片段添加到该父节点下最后返回添加后XML文件的内容
/// </remarks>
/// <param name="xmlDoc"></param>
/// <param name="xmlDocFrag">XML文档片段</param>
/// <param name="parentNodePath">父节点路径</param>
/// <returns>添加后XML文件的内容</returns>
public string AddChildNode(XmlDocument xmlDoc, XmlDocumentFragment xmlDocFrag, string parentNodePath)
{
this.xmlDoc = xmlDoc;
XmlElement selectEle = (XmlElement)xmlDoc.SelectSingleNode(parentNodePath);
selectEle.AppendChild(xmlDocFrag.FirstChild);
return this.xmlDoc.OuterXml;
}
/// <summary>
/// 替换子节点
/// </summary>
/// <remarks>
/// 该方法利用父节点路径选择该节点并用传入的XML文档片段替换该父节点下的第i个子节点最后返回替换后的XML文件的内容
/// </remarks>
/// <param name="xmlDoc"></param>
/// <param name="xmlDocFrag">XML文档片段</param>
/// <param name="parentNodePath">父节点路径</param>
/// <param name="i">第i个子节点</param>
/// <returns>替换后的XML文件的内容</returns>
public string ReplaceChildNode(XmlDocument xmlDoc, XmlDocumentFragment xmlDocFrag, string parentNodePath, int i)
{
this.xmlDoc = xmlDoc;
XmlElement selectEle = (XmlElement)xmlDoc.SelectSingleNode(parentNodePath);
XmlElement childEle = (XmlElement)selectEle.ChildNodes[i];
selectEle.ReplaceChild(xmlDocFrag.FirstChild,childEle);
return this.xmlDoc.OuterXml;
}
/// <summary>
/// 移除子节点
/// </summary>
/// <remarks>
/// 该方法利用传入的父节点名称选择该父节点并利用传入的子节点名称选择该子节点选定后使用父节点的RemoveChild方法移除子节点
/// 最后返回移除后XML的文件内容
/// </remarks>
/// <param name="parentNodeName">父节点名称</param>
/// <param name="childNodeName">子节点名称</param>
/// <returns>移除后XML的文件内容</returns>
public string RemoveChildNode(string parentNodeName, string childNodeName)
{
xmlDoc = new XmlDocument();
xmlDoc.Load(this._xmlPath);
XmlNodeList parentNodeList = xmlDoc.GetElementsByTagName(parentNodeName);
foreach (XmlNode parentNode in parentNodeList)
{
XmlNodeList childNodeList = parentNode.SelectNodes(childNodeName);
foreach (XmlNode childNode in childNodeList)
{
parentNode.RemoveChild(childNode);
}
}
return xmlDoc.OuterXml;
}
}
}
窗口程序代码如下:
namespace DOMSamples
{
using System;
using System.Xml;
using System.Text;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.Button button6;
private System.Windows.Forms.Button button7;
private System.Windows.Forms.Button button8;
private string xmlPath;
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.button5 = new System.Windows.Forms.Button();
this.button6 = new System.Windows.Forms.Button();
this.button7 = new System.Windows.Forms.Button();
this.button8 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.textBox1.Location = new System.Drawing.Point(8, 8);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBox1.Size = new System.Drawing.Size(776, 296);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "";
//
// button1
//
this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button1.Location = new System.Drawing.Point(8, 312);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(56, 23);
this.button1.TabIndex = 1;
this.button1.Text = "LoadXML";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button2.Location = new System.Drawing.Point(72, 312);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(96, 23);
this.button2.TabIndex = 2;
this.button2.Text = "LoadXMLReader";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button3.Location = new System.Drawing.Point(176, 312);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(56, 23);
this.button3.TabIndex = 3;
this.button3.Text = "SaveXML";
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// button4
//
this.button4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button4.Location = new System.Drawing.Point(240, 312);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(96, 23);
this.button4.TabIndex = 4;
this.button4.Text = "SaveXMLWriter";
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// button5
//
this.button5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button5.Location = new System.Drawing.Point(344, 312);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(80, 23);
this.button5.TabIndex = 5;
this.button5.Text = "Add Product";
this.button5.Click += new System.EventHandler(this.button5_Click);
//
// button6
//
this.button6.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button6.Location = new System.Drawing.Point(432, 312);
this.button6.Name = "button6";
this.button6.Size = new System.Drawing.Size(112, 23);
this.button6.TabIndex = 6;
this.button6.Text = "Replace Product";
this.button6.Click += new System.EventHandler(this.button6_Click);
//
// button7
//
this.button7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button7.Location = new System.Drawing.Point(552, 312);
this.button7.Name = "button7";
this.button7.Size = new System.Drawing.Size(88, 23);
this.button7.TabIndex = 7;
this.button7.Text = "Change Order";
this.button7.Click += new System.EventHandler(this.button7_Click);
//
// button8
//
this.button8.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button8.Location = new System.Drawing.Point(648, 312);
this.button8.Name = "button8";