简单的XML文件操作(xml文件生成,节点追加、遍历、修改、删除)

时间:2022-06-29 05:14:32

正题:xml文件如下:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--  编制人:DOCFlying  -->
<!--  编制时间:2007-08-05  -->
<KeywordsDefinition>
  <!--KeywordType:分为Keyword(关键字)、Control(控件类型缩写)、Variable(变量类型缩写)、Class(类名称缩写)-->
  <Keyword>
    <No.>1</No.>
    <KeywordName>i_[variable name]</KeywordName>
    <KeywordType>Variable</KeywordType>
    <Describe>int 型变量的缩写定义。如:int i_year = 2007;</Describe>
    <InputTime>2007-08-01 15:13:40</InputTime>
  </Keyword>
  <Keyword>
    <No.>2</No.>
    <KeywordName>l_[variable name]</KeywordName>
    <KeywordType>Variable</KeywordType>
    <Describe>long 型变量的缩写定义。如:long l_personal = 1500000000;</Describe>
    <InputTime>2007-08-01 15:14:10</InputTime>
  </Keyword>
  <Keyword>
    <No.>3</No.>
    <KeywordName>bl_[variable name]</KeywordName>
    <KeywordType>Variable</KeywordType>
    <Describe>boolean 型变量的缩写定义。如:boolean bl_flag = true;</Describe>
    <InputTime>2007-08-01 15:14:55</InputTime>
  </Keyword>
  <Keyword>
    <No.>6</No.>
    <KeywordName>us_[variable name]</KeywordName>
    <KeywordType>Variable</KeywordType>
    <Describe>ushort 型变量的缩写定义。如:ushort us_personal = 8;</Describe>
    <InputTime>2007-08-01 15:15:40</InputTime>
  </Keyword>
</KeywordsDefinition>

1)生成制定文件名的xml文件;
2)追加xml文件节点;
3)遍历xml文件的节点;
4)修改匹配值的xml文件的节点;
5)删除匹配值的xml文件节点;
主要运用了xml的操作类,熟悉了XPath表达的写法。下边代码省略了前台ASP.NET代码,只提供C#的主要代码,代码中没有容错,仅以说明解决的方法为目的。

代码如下:
1)生成制定文件名的XML文件:TextBox1制定文件名;TextBox2描述文档信息(文档开头备注);TextBox3制定xml开始标记。在生成xml的同时,也可以一并添加节点,如下面代码中已注释的部分。

 protected void Button1_Click(object sender, EventArgs e)
    ...{
        //生成一个新的xml文件;
        if (this.TextBox1.Text.Trim() == "" || this.TextBox3.Text.Trim() == "")
        ...{
            Response.Write("<script>alert('要生成的文件名称、文件的开始标记不能为空!');</script>");
            return;
        }

        XmlTextWriter _xmlWriter = new XmlTextWriter(MapPath("xml/" + TextBox1.Text.Trim() + ".xml"),System.Text.Encoding.UTF8);
        DateTime datime = DateTime.Now;
        _xmlWriter.Formatting = Formatting.Indented;
        _xmlWriter.WriteStartDocument(false);
        _xmlWriter.WriteComment("文档描述:" + TextBox2.Text.Trim());
        _xmlWriter.WriteComment("编制人:DOCFlying");
        _xmlWriter.WriteComment("编制时间:" + datime.Date.ToString("yyyy-MM-dd"));
        _xmlWriter.WriteStartElement(TextBox3.Text.Trim());
        _xmlWriter.WriteComment("KeywordType:分为Keyword(关键字)、Control(控件类型缩写)、Variable(变量类型缩写)");
        //_xmlWriter.WriteStartElement("Keyword");
        //_xmlWriter.WriteElementString("No.", "1");
        //_xmlWriter.WriteElementString("KeywordName", "ID");       
        //_xmlWriter.WriteElementString("KeywordType", "Keyword");
        //_xmlWriter.WriteElementString("Describe", "唯一序列索引编号。");
        //_xmlWriter.WriteElementString("InputTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        _xmlWriter.WriteFullEndElement();
        _xmlWriter.WriteEndDocument();
        _xmlWriter.Flush();
        _xmlWriter.Close();
    }

   2)追加节点:在追加节点是,为了确定节点No.的最大值,用了三种方法。其中第三种方法,用了遍历比较的办法,也是效率最差最笨的办法,是我最初的解决算法,而前两种是我再论坛中求教后改进的代码。第一种方法是在确保最后一个节点的No.值最大的情况下用的方法,第二种方法是在No.值大小顺序不定的情况下的解决办法。
         而在真正插入节点的时候,也用了两种方法。第一种方法是我最初的解决办法,第二种是在论坛求教后改经的代码(在此特别感谢BearRui(开心熊 | 来地球抢分)的指教,求教原文见论坛:http://community.csdn.net/Expert/topic/5695/5695643.xml?temp=.7378656)。两种方法均能实现追加节点的功能。最大的区别在于,方法一向XmlElement.DocumentElement中AppendChild()XmlElement;方法二向XmlNode中AppendChild()XmlElement。
       TextBox4设置No.值;TextBox5设置KeywordName值;DropDownList1确定KeywordType的值;TextBox6设置Describe的值。

    /**//// <summary>
    /// 向XML文件中插入节点。
    /// </summary>
    protected void Button2_Click(object sender, EventArgs e)
    ...{
        //向xml文档中插入节点;
        if (this.TextBox5.Text.Trim() == "" || this.TextBox6.Text.Trim() == "")
        ...{
            Response.Write("<script>alert('No.、KeywordName、Describe的值均不能为空!')</script>");
            return;
        }
        if (this.DropDownList1.SelectedItem.Value == "0")
        ...{
            Response.Write("<script>alert('Type值必须选择!')</script>");
            return;
        }
        if (this.TextBox1.Text.Trim() != "")
        ...{
            string filename = MapPath("xml/" + this.TextBox1.Text.Trim() + ".xml");
            XmlDocument xml_Doc = new XmlDocument();
            xml_Doc.Load(filename);
            //确定节点No.最大值,方法一:**********************************************         
            //如果xml文件的最后一个节点始终是最大的,可用以下的方法;
            //string maxNo = xml_Doc.DocumentElement.LastChild.FirstChild.InnerText;
            //确定节点No.最大值,方法一结束。******************************************

            //确定节点No.最大值,方法二:********************************************
            //查找xml文件节点No.的最大值;
            string str_xpath = "//No.[not(text() < //No./text())]";
            int maxNo;
            XmlNode xn_testnode = xml_Doc.SelectSingleNode(str_xpath);
            if (xn_testnode != null)
            ...{
                maxNo = Convert.ToInt32(xn_testnode.ChildNodes[0].InnerText);
                maxNo++;
            }
            else
            ...{
                maxNo = 0;
            }
            //确定节点No.最大值,方法二结束。**********************


            //确定节点No.最大值,方法三:**************************
            /**//*
            XPathNavigator xp_nav = xml_Doc.CreateNavigator();
            //下面这行代码生成XpathExpression表达式,不过可以省略,在xp_nav.Compile()中直接用字符的Xpath路径也可。
            //如:XPathNodeIterator xp_nodeite = xp_nav.Select("KeywordsDefinition/Keyword/No.")           
            XPathExpression xp_exp = xp_nav.Compile("KeywordsDefinition/Keyword/No.");
            int i_no = 0; //(int)xp_nav.Evaluate(xp_exp);
            XPathNodeIterator xp_nodeite = xp_nav.Select(xp_exp);

            if(xp_nodeite.Count == 0)
                goto TestEnd;

            while (xp_nodeite.MoveNext())
            {//寻找No.的最大值;            
                if (i_no < Convert.ToInt32(xp_nodeite.Current.Value))
                {
                    i_no = Convert.ToInt32(xp_nodeite.Current.Value);              
                }
            }
           
            i_no++;
            this.TextBox4.Text = i_no.ToString();
            //确定节点No.最大值,方法三结束****************************。


           //插入节点的方法一:
           XmlElement xml_ele = xml_Doc.CreateElement("Keyword");           

           XmlElement xml_no = xml_Doc.CreateElement("No.");
           xml_no.InnerText = i_no.ToString();
           //xml_no.InnerText = maxNo.ToString();
           xml_ele.AppendChild(xml_no);
          
           XmlElement xml_name = xml_Doc.CreateElement("Name");
           xml_name.InnerText = this.TextBox5.Text.Trim();
           xml_ele.AppendChild(xml_name);

           XmlElement xml_type = xml_Doc.CreateElement("Type");
           xml_type.InnerText = this.DropDownList1.SelectedItem.Text;
           xml_ele.AppendChild(xml_type);

           XmlElement xml_dec = xml_Doc.CreateElement("Describe");
           xml_dec.InnerText = this.TextBox6.Text.Trim();
           xml_ele.AppendChild(xml_dec);
           
           XmlElement xml_time = xml_Doc.CreateElement("InputTime");
           xml_time.InnerText = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
           xml_ele.AppendChild(xml_time);
           
           xml_Doc.DocumentElement.AppendChild(xml_ele);
           XmlTextWriter xml_writer = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
           xml_writer.Formatting = Formatting.Indented;           
           xml_Doc.WriteContentTo(xml_writer);
           xml_writer.Close();

       TestEnd:
           return;
            */
            //插入节点的方法二;
            XmlNode xml_node = xml_Doc.SelectSingleNode("KeywordsDefinition");
            XmlElement xml_ele = xml_Doc.CreateElement("Keyword");
            XmlElement xmlEle_no = xml_Doc.CreateElement("No.");
            xmlEle_no.InnerText = maxNo.ToString();
            xml_ele.AppendChild(xmlEle_no);

            XmlElement xe_name = xml_Doc.CreateElement("KeywordName");
            xe_name.InnerText = TextBox5.Text.Trim();
            xml_ele.AppendChild(xe_name);

            XmlElement xe_type = xml_Doc.CreateElement("KeywordType");
            xe_type.InnerText = DropDownList1.SelectedItem.Text;
            xml_ele.AppendChild(xe_type);

            XmlElement xe_des = xml_Doc.CreateElement("Describe");
            xe_des.InnerText = TextBox6.Text.Trim();
            xml_ele.AppendChild(xe_des);

            XmlElement xe_date = xml_Doc.CreateElement("InputTime");
            xe_date.InnerText = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            xml_ele.AppendChild(xe_date);           

            xml_node.AppendChild(xml_ele);
            xml_Doc.Save(filename);       
        }
    }
3)遍历xml文件的节点:这个功能的实现没那么轻松了,为了确定遍历到的当前节点,我设置用了static属性。方法一用了三个隐藏的TextBox,一个用来设置No.的最大值+1;一个用来设置No.的最小值-1;一个用来设置当前遍历的No.值。这样就可以实现xml结点的双向按顺序遍历,下面代码只实现了下后遍历查看。方法二虽然用static属性实现了功能,但是大家都知道,static的值在服务端是不变的,任何一个客户端对它的改变都会体现或影响其他的客户端。
TextBox7用来接受显示InputTime的值。

    /**//// <summary>
    /// 遍历xml文档节点;
    /// </summary>
    protected void Button5_Click(object sender, EventArgs e)
    ...{
        XmlDocument xd_document = LoadXML(TextBox1.Text.Trim());
        if (xd_document == null)
        ...{
            Response.Write("<script>alert("指定的文件不存在,或文件名称为空!请查证!")</script>");
            return;
        }
        //遍历文档节点之方法一***********************************
        int i_pos;
        if (h1.Text == string.Empty || h2.Text == string.Empty || h3.Text == string.Empty)
        ...{
            string str_maxstr = "//No.[not(text() < //No./text())]";
            string str_minstr = "//No.[not(text() > //No./text())]";
            XmlNode xn_maxNode = xd_document.SelectSingleNode(str_maxstr);
            XmlNode xn_minNode = xd_document.SelectSingleNode(str_minstr);
            int i_max, i_min;

            if (xn_maxNode != null || xn_minNode != null)
            ...{//向隐藏域赋值
                i_max = Convert.ToInt32(xn_maxNode.ChildNodes[0].InnerText) + 1;
                i_min = Convert.ToInt32(xn_minNode.ChildNodes[0].InnerText) - 1;
                i_pos = i_min;
                h1.Text = i_max.ToString();//最大值赋给隐藏域h1
                h2.Text = i_min.ToString();//最小值赋给隐藏域h2
                h3.Text = i_pos.ToString();//当前访问值赋给隐藏域h3
            }
            else
            ...{
                Response.Write("<script>alert("不能遍历空文档!")</script>");
                return;
            }
        }      
       
        i_pos = Convert.ToInt32(h3.Text);

      Skip:
        i_pos++;
        if (i_pos == Convert.ToInt32(h1.Text))
        ...{
            Response.Write("<script>alert("已经到了文档结尾!")</script>");
            return;
        }
       
        XmlNode xn_posNode = xd_document.SelectSingleNode("//No.[text() = "" + i_pos.ToString() + ""]");
        if (xn_posNode == null) goto Skip;
       
        TextBox4.Text = xn_posNode.ParentNode.SelectSingleNode("No.").InnerText;
        TextBox5.Text = xn_posNode.ParentNode.SelectSingleNode("KeywordName").InnerText;
        DropDownList1.Items[DropDownList1.SelectedIndex].Selected = false;
        for (int i_x = 0; i_x < DropDownList1.Items.Count; i_x++)
        ...{
            if (DropDownList1.Items[i_x].Text == xn_posNode.ParentNode.SelectSingleNode("KeywordType").InnerText)
            ...{
                DropDownList1.Items[i_x].Selected = true;
                break;
            }
        }
        TextBox6.Text = xn_posNode.ParentNode.SelectSingleNode("Describe").InnerText;
        TextBox7.Text = xn_posNode.ParentNode.SelectSingleNode("InputTime").InnerText;
        h3.Text = i_pos.ToString(); 
        //遍历文档节点之方法一:End
        //*******************************************
        /**//*遍历文档节点之方法二:
        if (!IsRead)
        {
            XPathNavigator xpn_nav = xd_document.CreateNavigator();
            XPathNodeIterator xnp_NIter = xpn_nav.Select("KeywordsDefinition/Keyword/No.");
            if (xnp_NIter.Count == 0) return;
            IsRead = true;
        }

        XmlDocument xd_newdoc = LoadXML(TextBox1.Text.Trim());
        //XmlNode xn_noede = xd_newdoc.SelectSingleNode("/Keyword/[No.=" + IDValue[NodeCount] + "]");
        XmlNodeList xn_noede = xd_newdoc.SelectNodes("KeywordsDefinition/Keyword");

        if (NodeCount >= xn_noede.Count)
        {
            Response.Write("<script>alert("已经到了文档的尾部!")</script>");
            return;
        }
        XmlElement my_xmlele = (XmlElement)xn_noede.Item(NodeCount);
        XmlNodeList my_nodelist = my_xmlele.ChildNodes;
        foreach (XmlNode xn_mynode in my_nodelist)
        {
            switch(xn_mynode.Name)
                    {
                        case "No.":
                            TextBox4.Text = xn_mynode.InnerText;
                            break;
                        case "KeywordName":
                            TextBox5.Text = xn_mynode.InnerText;
                            break;
                        case "KeywordType":
                            DropDownList1.Items[DropDownList1.SelectedIndex].Selected = false;
                            for (int y = 0; y < DropDownList1.Items.Count; y++)
                            {
                                if (DropDownList1.Items[y].Text == xn_mynode.InnerText)
                                {
                                    DropDownList1.Items[y].Selected = true;
                                    break;
                                }
                            }
                            break;
                        case "Describe":
                            TextBox6.Text = xn_mynode.InnerText;
                            break;
                        case "InputTime":
                            TextBox7.Text = xn_mynode.InnerText;
                            break;
                        default:
                            break;
                    }
        }
       
        NodeCount++;
        遍历文档节点之方法二:End */
    }
代码中用到的static属性的代码如下:

    private static bool bl_isRead = false;
    private static int i_nodeCount = 0;
    //确定遍历节点是否已经开始,
    //如果没有在读取第一个结点之后将其设置为true;
    private static bool IsRead
    ...{
        get ...{ return bl_isRead; }
        set ...{ bl_isRead = value; }
    }
    //获取或设置xml文档节点的总数;
    private static int NodeCount
    ...{
        get ...{ return i_nodeCount; }
        set ...{ i_nodeCount = value; }
    }
代码中还用到了两个方法:返回XmlDocument型的LoadXML(String XmlFileName);返回String型xml路径的XmlFilePath(string FilePath)。代码如下:

    /**//// <summary>
    /// 生成一个加载了xml文件的XmlDocument实例,并返回System.Xml.XmlDocument对象。
    /// </summary>
    /// <param name="XmlFileName">文件名称</param>
    /// <returns>操作成功返回XmlDocument对象,否则返回null。</returns>
    private XmlDocument LoadXML(String XmlFileName)
    ...{
        XmlDocument xd_doc = new XmlDocument();
        string filename = XmlFileName.Trim();
        //int i_strlen = filename.Length;
        if (filename != string.Empty)
        ...{
            filename = XmlFilePath(filename);
            xd_doc.Load(filename);
            return xd_doc;
        }
        else
        ...{
            return null;
        }
       
    }
    /**//// <summary>
    /// 构造文件路径字符串。
    /// </summary>
    /// <param name="FilePath">文件名称</param>
    /// <returns>操作成功返回string,否则返回 String.Empty。</returns>
    private String XmlFilePath(string FilePath)
    ...{
        if (FilePath != string.Empty)
        ...{
            int i_strlen = FilePath.Length;
            if (FilePath.Substring(i_strlen - 4, 4) != ".xml")
            ...{
                FilePath = MapPath("xml/" + FilePath + ".xml");
            }
            return FilePath;
        }
        else
        ...{
            return string.Empty;
        }
    }
4)修改匹配指定No.值的xml节点:此功能也用了两种方法来实现,方法二是我最初的实现方法,是不是比较笨拙?方法一也是在求教后改进过的代码,最起码看起来代码简单多了。

    /**//// <summary>
    /// 保存xml文档节点的修改;
    /// </summary>
    protected void Button4_Click(object sender, EventArgs e)
    ...{
        XmlDocument xd_document = this.LoadXML(TextBox1.Text.Trim());
        if (xd_document == null)
        ...{
            Response.Write("<script>alert("文件名称不能为空!")</script>");
            return;
        }
        //修改节点数据之方法一:×××××××××
        string str_xpath = "//No.[text() = "" + TextBox4.Text.Trim() + ""]";//此句代码与下句相同,只不过为XPath的简写方式;
        //string str_xpath = "KeywordsDefinition/Keyword/No.[text() = "" + TextBox4.Text.Trim() + ""]";
        XmlNode xn_testNode = xd_document.SelectSingleNode(str_xpath);
        if (xn_testNode != null)
        ...{
            xn_testNode.ParentNode.SelectSingleNode("KeywordName").InnerText = TextBox5.Text.Trim();
            xn_testNode.ParentNode.SelectSingleNode("KeywordType").InnerText = DropDownList1.SelectedItem.Text;
            xn_testNode.ParentNode.SelectSingleNode("Describe").InnerText = TextBox6.Text.Trim();
            xn_testNode.ParentNode.SelectSingleNode("InputTime").InnerText = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }
        else
        ...{
            Response.Write("<script>alert("当前文本没有匹配此值的节点供修改,请检查输入的修改匹配条件!")</script>");
            return;
        }
        //End ×××××××××××××××××××××

        /**//*修改节点数据之方法二:
        XmlNodeList xn_nodelist = xd_document.SelectNodes("KeywordsDefinition/Keyword");
        bool isdel = false;
        foreach (XmlNode xn_newnode in xn_nodelist)
        {
            XmlElement xe_newele = (XmlElement)xn_newnode;
            XmlNodeList xnl_mynode = xe_newele.ChildNodes;
           
            foreach (XmlNode xn_mynode in xnl_mynode)
            {               
                XmlElement xe_myele = (XmlElement)xn_mynode;
                if (xe_myele.Name == "No." && xe_myele.InnerText == TextBox4.Text.Trim())
                {
                    isdel = true;
                    break;
                }
            }
           
            if (isdel)
            {
                XmlNode xn_node1 = xe_newele.SelectSingleNode("KeywordName");
                xn_node1.InnerText = TextBox5.Text.Trim();

                XmlNode xn_node2 = xe_newele.SelectSingleNode("KeywordType");
                xn_node2.InnerText = DropDownList1.SelectedItem.Text;

                XmlNode xn_node3 = xe_newele.SelectSingleNode("Describe");
                xn_node3.InnerText = TextBox6.Text.Trim();
                break;
            }
        }
         End **/

        xd_document.Save(XmlFilePath(TextBox1.Text.Trim()));
        Response.Write("<script>alert("文件节点修改保存成功!")</script>");
    }
5)删除匹配指定No.值的xml节点:下面的代码也用了两种方法实现删除的功能。同样,方法二是我最初的实现方法,方法一是求教后的改进代码。

    /**//// <summary>
    /// 删除xml文档节点;
    /// </summary>
    protected void Button3_Click(object sender, EventArgs e)
    ...{
        XmlDocument xd_document = this.LoadXML(TextBox1.Text.Trim());
        if (xd_document == null)
        ...{
            Response.Write("<script>alert("文件名称不能为空!")</script>");
            return;
        }
        //删除节点之方法一:
        string str_xpath = "//No.[text() = "" + TextBox4.Text.Trim() + ""]";//此句代码与下句相同,只不过为XPath的简写方式;
        //string str_xpath = "KeywordsDefinition/Keyword/No.[text() = "" + TextBox4.Text.Trim() + ""]";c
        XmlNode xn_testNode = xd_document.SelectSingleNode(str_xpath);
        if (xn_testNode != null)
        ...{
            xn_testNode.ParentNode.ParentNode.RemoveChild(xn_testNode.ParentNode);
        }
        else
        ...{
            Response.Write("<script>alert("当前文本没有匹配此值的节点供删除,请检查输入的匹配条件!")</script>");
            return;
        }
        //删除节点之方法一:End


        /**//*
         * 删除节点之方法二:
        XmlNodeList xn_nodelist = xd_document.SelectNodes("KeywordsDefinition/Keyword");        
        bool isdel = false;
        foreach (XmlNode xn_newnode in xn_nodelist)
        {
            XmlElement xe_newele = (XmlElement)xn_newnode;
            XmlNodeList xnl_mynode = xe_newele.ChildNodes;
            foreach (XmlNode xn_mynode in xnl_mynode)
            {
                XmlElement xe_myele = (XmlElement)xn_mynode;
                if (xe_myele.Name == "No.")
                {
                    if (xe_myele.InnerText == TextBox4.Text.Trim())
                    {
                        //xn_mynode.ParentNode.ParentNode.RemoveChild(xn_mynode.ParentNode);
                        //上句代码和此foreach外的xn_newnode.ParentNode.RemoveChild(xn_newnode)功能相同;
                        isdel = true;
                        break;
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    break;
                }
            }
            if (isdel)
            {
                xn_newnode.ParentNode.RemoveChild(xn_newnode);
                break;
            }
        }
         End **/
       
        xd_document.Save(XmlFilePath(TextBox1.Text.Trim()));
        Response.Write("<script>alert("文件节点删除成功!")</script>");
    }
好了,到这里关于xml文档的生成、追加、修改、删除、遍历都简单的实现了。可能确实很笨拙,不过不要紧,欢迎各位方家提出更好的实现方法,让小弟再学习学习。谢谢!


本文来自CSDN博客,转载请标明出处: