文档对象模型操作xml文档

简介 :文档对象模型(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文档:

  1. 指定xml文档路径路程或者URL
  2. 包含xml文档数据的文件流对象
  3. 包含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文档树中的 某个或某些元素和节点,去获得相关的信息和数据值。

  1. Ge他ElementByTagName()方法
  2. GetElementById()方法
  3. SelectNodes()方法
  4. 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综合实例

文档对象模型操作xml文档

 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类提供的事件过程,这些事件过程分别遵循事前或者事后激发模式。

文档对象模型操作xml文档 NodeChanged

当属于该文档的节点的 Value 已被更改时发生。

文档对象模型操作xml文档 NodeChanging

当属于该文档的节点的 Value 将被更改时发生。

文档对象模型操作xml文档 NodeInserted

当属于该文档的节点已被插入另一个节点时发生。

文档对象模型操作xml文档 NodeInserting

当属于该文档的节点将被插入另一个节点时发生。

文档对象模型操作xml文档 NodeRemoved

Occurs when a node belonging to this document has been removed from its parent.

文档对象模型操作xml文档 NodeRemoving

当属于该文档的节点将从文档中移除时发生。

表中的事件都接受一个XmlNodeChangeEventArgs类型的参数

下面提供这个类型参数的一些属性

文档对象模型操作xml文档 Action

获取一个值,该值指示正在发生哪种类型的节点更改事件。

文档对象模型操作xml文档 NewParent

获取操作完成后 ParentNode 的值。

文档对象模型操作xml文档 NewValue

获取节点的新值。

文档对象模型操作xml文档 Node

获取正被添加、移除或更改的 XmlNode

文档对象模型操作xml文档 OldParent

获取操作开始前的 ParentNode 的值。

文档对象模型操作xml文档 OldValue

获取节点的原始值。

上一篇:scala 加载与保存xml文档


下一篇:C# 使用XmlDocument类对XML文档进行操作