简介 :文档对象模型(DOM)是一种用于处理xml文档的API函数集。
2.1文档对象模型概述
按照W3C的定义,DOM是“一种允许程序或脚本动态地访问更新文档内容,结构和样式的、独立于平台和语言的规范化接口。DOM是表示文档(比如HTML和XML)和访问、操作构成文档的各种元素的应用程序接口,它以树状结构表示HTML和XML文档,定义了遍历这个树和检查、修改树的节点的方法和属性。
DOM的核心API还允许你创建和填充文件、加载文档并保存。
2.2DOM实现
微软的net框架在Systemx.xml命名空间提供了一系列的类用于DOM实现,xmlDocument是NET中Dom实现的核心类之一。正如其他的DOM解析器一样,该类是NET框架的DOC解析器。
xmlDocument将XML文档视为树状结构,他装在xml文档并在内存中构建该文档的树状结构。XmlDocument类代表了一个xml文档、,它支持xml的增删改查;
xmlNode代表一个节点。
xml文档组成 部分 | 对应的类 |
Document Element(文档元素) | XmlElement |
Processing Instructions(处理指令) | XmlProcessingIntruction |
Element(元素) | XmlElement |
Attribute(属性) | XmlAttribute |
Text Values(文本值) | XmlText |
Nodes(节点) | XmlNode |
表中所提及的类都直接或者间接的继承了抽象类的XmlNode。
2.3应用实例
2.3.1装载xml文档
XmlDocument类允许你通过三种方式打开一个xml文档:
- 指定xml文档路径路程或者URL
- 包含xml文档数据的文件流对象
- 包含xml文档数据的字符串
接来用这三种方法尝试打开xml文档。代码如下:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void btnopen_Click(object sender, EventArgs e)
{
try
{
XmlDocument doc = new XmlDocument();
if (rdbURL.Checked)
{
doc.Load(txtpath.Text);
}
if (rdbstream.Checked)
{
FileStream stream = new FileStream(txtpath.Text,FileMode.Open);
doc.Load(stream);
stream.Close();
}
if (rdbstring.Checked)
{
doc.LoadXml(txtpath.Text);//加载报错,Loading从指定的字符串中加载xml文档。
doc.LoadXml("<customer ><firstname>Ernestine</firstname><lastname>Borrison</lastname><homephone>(445) 269-7742</homephone><notes>123</notes></customer>");
//
} MessageBox.Show("XML Document Opened Successfully!");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
xmlDocument类具有俩个重要的方法:Load()和LoadXml()用于加载文档。Load方法通过指定xml文档的文件路径、URL或指向XML文档的流对象来打开XML 文档。
LoadXml方法中则通过指定包含xml文档的字符串来打开xml文档。在这个例子中,LoadXml加载的是文件的路径,导致加载无法成功,讲字符串替换为含有根节点的字符串即可,这个字符串中的节点并不一定是xml文档的根节点,是你选取的这个字符串中的根节点,其他节点应该包含在这个节点的内部,不能含有多个同等级的节点。
2.3.2遍历xml文档
一个xml文档可以包含一个或者对个节点,而每一个节点又可以包含多个子节点,xmlnode类具有一个叫Childnoes的集合体,该集合体包好某种条件下的所有子节点。net框架中与DOM 相关联的其他许多类都直接或者间接的继承自XmlNode类。因而这些类可以调用childNodes集合体。
例子代码:
private void btnload_Click(object sender, EventArgs e)
{
XmlDocument _doc = new XmlDocument();//创建实例
_doc.Load(Application.StartupPath + "/Customers.xml");//加载文件 TreeNode _root = new TreeNode(_doc.DocumentElement.Name);//documentElement 属性可返回文档的根节点
treeView1.Nodes.Add(_root); foreach (XmlNode node in _doc.DocumentElement.ChildNodes)
{
TreeNode _customer = new TreeNode("Customer ID : " + node.Attributes["customerid"].Value);//Attributes表示获取对应的属性信息 _root.Nodes.Add(_customer);
if (node.HasChildNodes)
{
foreach (XmlNode childnode in node.ChildNodes)
{
TreeNode _customer2 = new TreeNode(childnode.Name + " : " + childnode.InnerText);//InnerText获取节点的内部数据 。。。
_customer.Nodes.Add(_customer2);
}
}
}
}
2.3.3查询特殊元素和节点
在实际的使用中我们使用下面这几种方法来查询xml文档树中的 某个或某些元素和节点,去获得相关的信息和数据值。
- Ge他ElementByTagName()方法
- GetElementById()方法
- SelectNodes()方法
- SelectSingleNode()方法
1、XmlDcument类的GetElementByTagName()方法以节点的标签名为输入参数。并返回所有具有相同标签名的节点。这些节点包含在一个XmlNodeList类的实例中。
XmlNodeList类代表一个XmlNode对象的集合。代码如下:
public partial class Form1 : Form
{
#region Constructor
public Form1()
{
InitializeComponent();
}
#endregion #region Variables private XmlNodeList list = null;//代表一个XmlNode对象的集合、
#endregion
private void btnsearch_Click(object sender, EventArgs e)
{
lstresult.Items.Clear(); XmlDocument _doc = new XmlDocument();
_doc.Load(Application.StartupPath + "/customers.xml"); list = _doc.GetElementsByTagName(txttag.Text);//通过标签名获取list foreach (XmlNode node in list)
{
lstresult.Items.Add(node.Name);
}
} private void lstresult_SelectedIndexChanged(object sender, EventArgs e)
{
txtresult.Text = list[lstresult.SelectedIndex].InnerText;
}
2、应用GetElementByld方法
如果xml文档中存在一个具有唯一值的属性,比如人民的身份证这个属性。在查找特殊元素或者节点时,可应用GetElementByld()方法加以实现,其实现方式类似于应用主键在数据库中
查询相应的记录。问题在XmlDocument类不能自动的指定元素的某个特殊的属性作为元素的主键,因此在应用这个方法前,必须在xml文档中通过DTD或者Schema技术指定元素的某个属性作为元素的唯一的“主键”,同时使XmlDocument类能够将该属性视为元素的“主键”。
声明主键的代码如下:
<!DOCTYPE customers[
<!ELEMENT customers ANY>
<!ELEMENT customer ANY>
<!ELEMENT firstname ANY>
<!ELEMENT lastname ANY>
<!ELEMENT homephone ANY>
<!ELEMENT notes ANY>
<!ATTLIST customer customerid ID #REQUIRED>
]>
注意这行代码<!ATTLIST customer customerid ID #REQUIRED>,在此我们将属性customer id 标记为ID并同时规定其实唯一的(#REQUIRED)
这个方法的返回值是包含相应节点数据的XmlElement类的实例对象。
private void Form1_Load(object sender, EventArgs e)
{
doc = new XmlDocument();
doc.Load(Application.StartupPath+"/Customers.xml");
foreach(XmlNode node in doc.DocumentElement.ChildNodes)
{
string _strid=node.Attributes["customerid"].Value;
cmbID.Items.Add(_strid);
}
} private void cmbID_SelectedIndexChanged(object sender, EventArgs e)
{
XmlElement _xel = doc.GetElementById(cmbID.SelectedItem.ToString());
lblfirst.Text = _xel.ChildNodes[].InnerText;
lbllast.Text = _xel.ChildNodes[].InnerText;
lblphone.Text = _xel.ChildNodes[].InnerText;
lblnote.Text = _xel.ChildNodes[].InnerText;
}
3、应用SelectNodes()方法
在某些情况下,我们需要查询xml文档中付某中或者某些条件的节点。SelectNodes()可以满足这种要求,该方法可以根据查询条件过滤得到符合条件的节点。
返回值一个包含所有有效节点得到XmlNodeList实例对象。
public partial class Form1 : Form
{
#region ariables private XmlNodeList list = null;
#endregion #region Constructor public Form1()
{
InitializeComponent();
}
#endregion
private void btnsearch_Click(object sender, EventArgs e)
{
lstresult.Items.Clear();
XmlDocument _doc = new XmlDocument();
_doc.Load(Application.StartupPath + "/Customers.xml");
if (rdbfirst.Checked)
{
//string str = string.Format("//customer[./firstname/text()='{0}']", txtinput.Text);
//
string str = string.Format("//customer[./homephone[./quhao/text()='{0}']]", txtinput.Text);
//////customer[./firstname/text()='John']
list = _doc.SelectNodes(str);
}
if (rdblast.Checked)
{
list = _doc.SelectNodes(string.Format("//customer[./lastname/text()='{0}']", txtinput.Text));
}
foreach (XmlNode node in list)
{
lstresult.Items.Add(node.Attributes["customerid"].Value);
} } private void btndetail_Click(object sender, EventArgs e)
{
if (lstresult.SelectedIndex < )
{
MessageBox.Show("Please Selected a Customer ID");
}
else
{
lblfirst.Text = list[lstresult.SelectedIndex].ChildNodes[].InnerText;
lbllast.Text = list[lstresult.SelectedIndex].ChildNodes[].InnerText;
lblphone.Text = list[lstresult.SelectedIndex].ChildNodes[].InnerText;
lblnote.Text = list[lstresult.SelectedIndex].ChildNodes[].InnerText;
}
}
4、应用selectSingleNode()方法
该刚方法的不同于selectNodes的是:方法仅返回符合条件的第一个节点。
2.4修改XML文档
对XML文档的修改包括添加或者插入新节点,删除已存在节点、次该节点的相关数据或者属性。DOM 是一个读写型的解释器,因此dom也有提供许多函数方法和类允许你修改文档。
2.4.1 Save方法
save方法保存文件到指定的位置。 该方法传入的参数为XmlWriter、XmlTextWriter或者字符串。
string filename=@“C:\books.xml”;
XmlDocument xmlDoc= new XmlDocument();
xmlDoc.Load(filename);
XmlTextWriter writer = new XmlTextWriter("c:\\domtest.xml",null);
writer.Formatting=Formatting.Indented;
xmlDoc.Save(writer);
//你也可以使用一个文件名或Console.Out保存文档,或者将文档的内容输出到屏幕上
xmlDoc.Save("c:\\domtest.xml");
xmlDoc.Save(Console.Out);
2.4.2 XmlDocumentFragment类
在xml 文档中插入部分内容或者节点时,用到这个类=》这个类自XmlNode派生。=>通过xml文档的CreateDocumentFragment()方法来创建这个类的实例。
该实例的InnerXml属性代表当前节点的子节点。
XmlDocumentFragment docFrag=xmlDoc.CreateDocumentFragment();
2.4.3 XmlElement类
XmlElement代表文档中的一个元素,这个类继承自XmlLinkedNode,XmlLinkedNode类继承自XmlNode。XmlLinkedNode有俩个属性:NextSibing和PreviousSibling、代表与当前节点处于同一个层次的下一个和以前的节点。
下面网址链接此类的常用方法:网址链接
2.4.4 添加节点到XML 文档中
AppendChild()方法添加节点到文档中,方法接受一个XmlNode类类型的单个参数。xmldocument的creatxxx方法可以创建不同的节点,AppendChild可以将他们加到文档中。
添加评论节点代码:xmlDoc.AppendChild(nodel);
添加元素节点到文档中:xmlDoc.DocumentElement.AppendChild(nodel);
2.4.5 删除和更换节点
XmlNode类的RemoveAll()方法可以删除所有元素和节点的属性、方法RemoveChild()仅用于删除指定的子节点。
代码:XmlNode root= xmlDoc.DocumentElement;root.RemoveALll();
ReplaceChild()方法用于一个新的节点替换旧的节点rootNode.ReplaceChild(xmlDocFragment,rootNode.LastChild);
2.4.6 XML片段插入到xml文档中
XmlNode类提供相应的方法将xml片段插入到xml文档中,例如:InsertAfter()方法在当前节点之后插入一个文档或者元素。
该方法需要俩个参数,1:XmlDocumentFragment对象,2:要在其中插入片段的位置。(插入位置)
aNode.InsertAfter(xmlDocFragment,aNode.LastChild);
2.4.7添加属性到节点中
使用XmlElement类的SetAttributeNode()方法添加节点的属性。
XmlElement newElem=xmlDoc.CreateElement("NewElement");
//创建指定名称的元素
XmlAttribute newAttr=xmlDoc.CreateAttribute("NewAttribute");
newElem.SetAttributeNode(newAttr);
2.5综合实例
public partial class Form1 : Form
{
#region Variables private XmlDocument doc;
private int nodeindex = ; private bool isadd = false;
#endregion #region Constructor public Form1()
{
InitializeComponent(); }
#endregion #region Methods private void AddItemsIntoCombBox(XmlDocument _doc)
{
cmbID.Items.Clear();
foreach (XmlNode _node in _doc.DocumentElement.ChildNodes)
{
cmbID.Items.Add(_node.Attributes["customerid"].Value);
}
}
private void NodeRemoved(object sender, XmlNodeChangedEventArgs e)
{
MessageBox.Show("Node " + e.Node.Name + " removed successfully!");
} private void NodeInserted(object sender, XmlNodeChangedEventArgs e)
{
if (isadd)
{
MessageBox.Show("Node " + e.Node.Name + " added successfully!");
}
isadd = false;
} private void NodeChanged(object sender, XmlNodeChangedEventArgs e)
{
MessageBox.Show("Node " + e.Node.Name + " changed successfully!");
}
private void FillControlters()
{
XmlNode _nod = doc.DocumentElement.ChildNodes[nodeindex];
cmbID.Text = _nod.Attributes["customerid"].Value;
txtfname.Text = _nod.ChildNodes[].InnerText;
txtlname.Text = _nod.ChildNodes[].InnerText;
txtphone.Text = _nod.ChildNodes[].InnerText;
txtnote.Text = _nod.ChildNodes[].InnerText; this.UpdateInformation();
}
private void UpdateInformation()
{
lblinformation.Text = "Customer " + (nodeindex + ) + " of " + doc.DocumentElement.ChildNodes.Count.ToString();
}
#endregion private void Form1_Load(object sender, EventArgs e)
{
doc = new XmlDocument();
doc.Load(Application.StartupPath + "/customers.xml"); this.AddItemsIntoCombBox(doc); this.FillControlters(); doc.NodeChanged += new XmlNodeChangedEventHandler(NodeChanged);
doc.NodeInserted += new XmlNodeChangedEventHandler(NodeInserted);
doc.NodeRemoved += new XmlNodeChangedEventHandler(NodeRemoved); } private void btnadd_Click(object sender, EventArgs e)
{
if ((txtfname.Text == "") || (txtlname.Text == "") || (txtphone.Text == "") || (txtnote.Text == ""))
{
MessageBox.Show("Please fill up all items of customer!");
return;
}
XmlElement _customer = doc.CreateElement("customer");
XmlElement _firstname = doc.CreateElement("firstname");
XmlElement _lastname = doc.CreateElement("lastname");
XmlElement _homephone = doc.CreateElement("homephone");
XmlElement _notes = doc.CreateElement("notes"); XmlAttribute _customerid = doc.CreateAttribute("customerid");
_customerid.Value = cmbID.Text; XmlText _firstnametext = doc.CreateTextNode(txtfname.Text);
XmlText _lastnametext = doc.CreateTextNode(txtlname.Text);
XmlText _homephonetext = doc.CreateTextNode(txtphone.Text);
XmlCDataSection _notestext = doc.CreateCDataSection(txtnote.Text); _customer.Attributes.Append(_customerid);
_customer.AppendChild(_firstname);
_customer.AppendChild(_lastname);
_customer.AppendChild(_homephone);
_customer.AppendChild(_notes); _firstname.AppendChild(_firstnametext);
_lastname.AppendChild(_lastnametext);
_homephone.AppendChild(_homephonetext);
_notes.AppendChild(_notestext); isadd = true; doc.DocumentElement.AppendChild(_customer);
doc.Save(Application.StartupPath + "/Customers.xml"); this.AddItemsIntoCombBox(doc); this.UpdateInformation();
} private void btnupdate_Click(object sender, EventArgs e)
{
if ((txtfname.Text == "") || (txtlname.Text == "") || (txtphone.Text == "") || (txtnote.Text == ""))
{
MessageBox.Show("Please fill up all items of customer!");
return;
}
XmlNode _node = doc.SelectSingleNode("//customer[@customerid='" + cmbID.SelectedItem + "']");
if (_node != null)
{
if (_node.ChildNodes[].InnerText != txtfname.Text)
_node.ChildNodes[].InnerText = txtfname.Text;
if (_node.ChildNodes[].InnerText != txtlname.Text)
_node.ChildNodes[].InnerText = txtlname.Text;
if (_node.ChildNodes[].InnerText != txtphone.Text)
_node.ChildNodes[].InnerText = txtphone.Text;
if (_node.ChildNodes[].InnerText != txtnote.Text)
{
XmlCDataSection _notes = doc.CreateCDataSection(txtnote.Text);
isadd = true;
_node.ChildNodes[].ReplaceChild(_notes, _node.ChildNodes[].ChildNodes[]);
}
}
doc.Save(Application.StartupPath + "/Customers.xml");
} private void btndelete_Click(object sender, EventArgs e)
{
XmlNode _node = doc.SelectSingleNode("//customer[@customerid='" + cmbID.SelectedItem + "']");
if (_node != null)
{
doc.DocumentElement.RemoveChild(_node);
}
doc.Save(Application.StartupPath + "/Customers.xml"); nodeindex = ;
this.FillControlters();
this.UpdateInformation();
this.AddItemsIntoCombBox(doc);
} private void btnfirst_Click(object sender, EventArgs e)
{
nodeindex = ;
this.FillControlters();
} private void btnprevious_Click(object sender, EventArgs e)
{
nodeindex--;
if (nodeindex < )
{
nodeindex = ;
}
this.FillControlters();
} private void btnnext_Click(object sender, EventArgs e)
{
nodeindex++;
if (nodeindex >= doc.DocumentElement.ChildNodes.Count)
{
nodeindex = doc.DocumentElement.ChildNodes.Count - ;
}
this.FillControlters();
} private void btnlast_Click(object sender, EventArgs e)
{
nodeindex = doc.DocumentElement.ChildNodes.Count - ;
this.FillControlters();
}
2.6处理空白
加载文档时,默认情况下,XMLDocument类忽略空白。通过设置PreserveWhiteSpace的布尔型属性来控制是否需要空白内容,true将保存空白内容,false将不保留空白内容。
2.7XmlDocument类的事件
当修改xml 文档时,会激发小毛驴document类提供的事件过程,这些事件过程分别遵循事前或者事后激发模式。
NodeChanged |
当属于该文档的节点的 Value 已被更改时发生。 |
|
NodeChanging |
当属于该文档的节点的 Value 将被更改时发生。 |
|
NodeInserted |
当属于该文档的节点已被插入另一个节点时发生。 |
|
NodeInserting |
当属于该文档的节点将被插入另一个节点时发生。 |
|
NodeRemoved |
Occurs when a node belonging to this document has been removed from its parent. |
|
NodeRemoving |
当属于该文档的节点将从文档中移除时发生。 |
表中的事件都接受一个XmlNodeChangeEventArgs类型的参数
下面提供这个类型参数的一些属性
Action |
获取一个值,该值指示正在发生哪种类型的节点更改事件。 |
|
NewParent |
获取操作完成后 ParentNode 的值。 |
|
NewValue |
获取节点的新值。 |
|
Node |
获取正被添加、移除或更改的 XmlNode。 |
|
OldParent |
获取操作开始前的 ParentNode 的值。 |
|
OldValue |
获取节点的原始值。 |