文档对象模型操作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文档。代码如下:

 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);
            }
        }
    }
View Code

 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);
                    }
                }
            }
        }
View Code

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;
        }
View Code

    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>
]>
View Code

  注意这行代码<!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[0].InnerText;
            lbllast.Text = _xel.ChildNodes[1].InnerText;
            lblphone.Text = _xel.ChildNodes[2].InnerText;
            lblnote.Text = _xel.ChildNodes[3].InnerText;
        }
View Code

  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 < 0)
            {
                MessageBox.Show("Please Selected a Customer ID");
            }
            else
            {
                lblfirst.Text = list[lstresult.SelectedIndex].ChildNodes[0].InnerText;
                lbllast.Text = list[lstresult.SelectedIndex].ChildNodes[1].InnerText;
                lblphone.Text = list[lstresult.SelectedIndex].ChildNodes[2].InnerText;
                lblnote.Text = list[lstresult.SelectedIndex].ChildNodes[3].InnerText;
            }
        }
View Code

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);
View Code

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 = 0;

        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[0].InnerText;
            txtlname.Text = _nod.ChildNodes[1].InnerText;
            txtphone.Text = _nod.ChildNodes[2].InnerText;
            txtnote.Text = _nod.ChildNodes[3].InnerText;

            this.UpdateInformation();
        }
        private void UpdateInformation()
        {
            lblinformation.Text = "Customer " + (nodeindex + 1) + " 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[0].InnerText != txtfname.Text)
                    _node.ChildNodes[0].InnerText = txtfname.Text;
                if (_node.ChildNodes[1].InnerText != txtlname.Text)
                    _node.ChildNodes[1].InnerText = txtlname.Text;
                if (_node.ChildNodes[2].InnerText != txtphone.Text)
                    _node.ChildNodes[2].InnerText = txtphone.Text;
                if (_node.ChildNodes[3].InnerText != txtnote.Text)
                {
                    XmlCDataSection _notes = doc.CreateCDataSection(txtnote.Text);
                    isadd = true;
                    _node.ChildNodes[3].ReplaceChild(_notes, _node.ChildNodes[3].ChildNodes[0]);
                }
            }
            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 = 0;
            this.FillControlters();
            this.UpdateInformation();
            this.AddItemsIntoCombBox(doc);
        }

        private void btnfirst_Click(object sender, EventArgs e)
        {
            nodeindex = 0;
            this.FillControlters();
        }

        private void btnprevious_Click(object sender, EventArgs e)
        {
            nodeindex--;
            if (nodeindex < 0)
            {
                nodeindex = 0;
            }
            this.FillControlters();
        }

        private void btnnext_Click(object sender, EventArgs e)
        {
            nodeindex++;
            if (nodeindex >= doc.DocumentElement.ChildNodes.Count)
            {
                nodeindex = doc.DocumentElement.ChildNodes.Count - 1;
            }
            this.FillControlters();
        }

        private void btnlast_Click(object sender, EventArgs e)
        {
            nodeindex = doc.DocumentElement.ChildNodes.Count - 1;
            this.FillControlters();
        }
View Code

2.6处理空白

  加载文档时,默认情况下,XMLDocument类忽略空白。通过设置PreserveWhiteSpace的布尔型属性来控制是否需要空白内容,true将保存空白内容,false将不保留空白内容。

 

2.7XmlDocument类的事件

   当修改xml 文档时,会激发小毛驴document类提供的事件过程,这些事件过程分别遵循事前或者事后激发模式。

System_CAPS_pubevent NodeChanged

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

System_CAPS_pubevent NodeChanging

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

System_CAPS_pubevent NodeInserted

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

System_CAPS_pubevent NodeInserting

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

System_CAPS_pubevent NodeRemoved

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

System_CAPS_pubevent NodeRemoving

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

 

 

 

 

 

 

 

 

 

 

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

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

System_CAPS_pubproperty Action

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

System_CAPS_pubproperty NewParent

获取操作完成后 ParentNode 的值。

System_CAPS_pubproperty NewValue

获取节点的新值。

System_CAPS_pubproperty Node

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

System_CAPS_pubproperty OldParent

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

System_CAPS_pubproperty OldValue

获取节点的原始值。

posted @ 2016-02-29 23:29  ZHLBKY  阅读(536)  评论(0编辑  收藏  举报