代码改变世界

C#操作XML简析系列(1)之增删修改查

2013-04-12 10:35  立雪三尺  阅读(1738)  评论(4编辑  收藏  举报

熟悉的陌生人


提起XML,并不陌生,它随处可见,例如,网站的web.config,RSS.xml.可自定义节点,还可充当数据库,可是如果真的静心来看看它,却只知道是类似于HTML的节点标签文件,可以这样用可以那样用,花样繁多,并不是非常的了解他。

XML,可扩展标记语言(Extensible Markup Language, XML),作为一个小菜鸟,可能并无法从定义上是真正的了解XML是什么,或许我们可以从他的用途上去认识,这样比记忆那些空洞的定义更有帮助。下面是XML的几种招人喜爱的用途,主要分为文档型和数据型:(维基百科

  • 丰富文件-自定文件描述并使其更丰富,自定义XML+XSLT=>HTML,最常见的文档型应用之一。
  • 源数据-XML作为微型数据库,在一些系统的运用做一些轻量级的存储,避免动用复杂的大型数据库,这里要注意,数据库和数据库系统,这两个不同的概念。
  • 信息传递的载体-最典型的就是 WEB SERVICE,将数据包装成XML来传递,但是这里的XML已经有了特定的规格,即SOAP。
  • 配置文档-描述软件设置的参数,如web.config

  HTML与XML之间的关系

  1、XML可以视作对HTML的补充。

  2、HTML 的设计目标是显示数据并集中于数据外观,而XML的设计目标是描述数据并集中于数据的内容。

  3、与HTML相似,XML不进行任何操作。虽然XML标记可用于描述订单之类的项的结构,但它不包含可用于发送或处理该订单以及确保按该订单交货的任何代码,其他人必须编写代码来实际对XML格式的数据执行这些操作。与 HTML 不同,XML 标记由架构或文档的作者定义,并且是无限制的。HTML 标记则是预定义的;HTML 作者只能使用当前 HTML 标准所支持的标记。

  4、XML 标记由架构或文档的作者定义,并且是无限制的。HTML 标记则是预定义的;HTML 作者只能使用当前 HTML 标准所支持的标记。

总之,XML实际是一种抽象的语言,只是不如常用的传统语言那么具体。

 

准备工作


 

为了涵盖XML的扩展用法,.NET Framework包含了System.XML命名空间,这个命名空间包含了许多处理XML的类。增删修改有关的类有以下几个:

XMLReader(这是一个抽象类),它拥有三个常用子类 XMLNodeReader                                          
XMLTextReader
XMLValidatingReader
XMLWriter,同XMLReader一样,它也是一个抽象类,有两个常用子类 XMLTextWriter
XmlQueryWriter
DOM模型 XmlLinkedNode  (有子类XmlElement)  
XmlDocument
XmlAttribute
XmlEntity

操作XML,首先我们先写个XML的Demo:Account.xml,如下所示:

<Server>
  <Accounts>
    <Account>
      <Email>Carl@happy.com</Email>
      <IsAdmin>True</IsAdmin>
      <Password>123</Password>
    </Account>
   <Account>
</Accounts> </Server>

 将它存在指定路径下,我本地存放路径为 C:\test\Accounts.xml

增删改查


 

  1. 为了更方便地处理对Account节点,我们首先对Account以及其子节点建一个对象类,后面增删改查方法处理的都是Account对象,这样操作更加方便快捷一点;
    public class Account
    {
        public string Email { get; set; }
        public bool IsAdmin { get; set; }
        public string Password { get; set; }
    }

 

    2.   创建class AccountXML,这个类中有5个静态方法,主要是针对account.xml的操作。

  • loadXml()方法,主要加载C:\test\Accounts.xml,若是路径不存在或者xml格式不正确导致加载异常,该方法会重写Accounts.xml并加载,返回一个XmlDocument对象 
       public static XmlDocument loadXml()
       {
           XmlDocument Doc = new XmlDocument();
           //check the path 
           try
           {
               Doc.Load("C:\\test\\Accounts.xml");
           }
           catch (Exception e)
           {
               XmlDocument newDoc = new XmlDocument();   
               XmlElement root = newDoc.CreateElement("Server");
               newDoc.AppendChild(root);
               XmlElement childAccounts = newDoc.CreateElement("Accounts");
               root.AppendChild(childAccounts);
               newDoc.Save("C:\\test\\Accounts.xml");
               Doc.Load("C:\\test\\Accounts.xml");
           }
           return Doc;
       }
  •  xmlReader()方法,这个方法对xml进行读取,返回一个List<Account>对象
        //read server account.xml
       public static  List<Account> xmlReader() {
           List<Account> acccountList = new List<Account>();
           XmlDocument doc = loadXml();
           XmlNodeList nodeList= doc.GetElementsByTagName("Account");
           Account account = new Account();
           foreach (XmlNode node in nodeList)
           {
               //assign values
               account.Email = node.SelectSingleNode("Email").InnerText.ToString();
               account.IsAdmin = node.SelectSingleNode("IsAdmin").InnerText == "True";
               account.Password = node.SelectSingleNode("Password ").InnerText.ToString();
               acccountList.Add(account);
           }
            return acccountList;
         }
  •  xmlWriter(Account acc)方法,这个方法有一个Account对象参数,它会被写入xml
        //write server account.xml
       public static void xmlWriter(Account acc) 
       {
           XmlDocument xmlDoc = loadXml();
           XmlNode accountsNode = xmlDoc.SelectSingleNode("Server/Accounts");
           XmlElement accountNode = xmlDoc.CreateElement("Account");
           XmlElement email = xmlDoc.CreateElement("Email");
           XmlElement isAdmin = xmlDoc.CreateElement("IsAdmin");
           XmlElement password = xmlDoc.CreateElement("Password");

           email.InnerXml = acc.Email.ToString();
           isAdmin.InnerXml = acc.IsAdmin.ToString();
           password.InnerXml = acc.Password.ToString();

           accountNode.AppendChild(email);
           accountNode.AppendChild(isAdmin);
           accountNode.AppendChild(password);

           accountsNode.AppendChild(accountNode);
           //save doc
           try
           {
               xmlDoc.Save("C:\\test\\Accounts.xml");
           }
           catch (Exception save)
           {
               throw save;
           }
       }

 xmlUpdate(Account acc)方法,这个方法有一个Account对象参数,如果该对象不存在,它会被写入xml ,若存在,则不被写入,注意:这个方法里用来判别对象是否存在的对比参数为Email属性

  public static void  xmlUpdate(Account acc) {
           XmlDocument xmlDoc = loadXml();
           XmlNodeList accountList = xmlDoc.SelectSingleNode("Server/Accounts").ChildNodes;
           foreach (XmlNode account in accountList) {
               //if account exists
               if (acc.Email.ToString() == account.SelectSingleNode("Email").InnerXml.ToString())
               {
                   XmlElement accountElement = (XmlElement)account;
                   XmlNodeList accountChild = account.ChildNodes;
                   foreach (XmlNode child in accountChild)
                   {
                       XmlElement eleChild = (XmlElement)child;
                       switch (eleChild.Name)
                       {
                           case "EMAIL":
                               eleChild.InnerText = acc.Email;
                               break;
                           case "IsAdmin":
                               eleChild.InnerText = acc.IsAdmin.ToString();
                               break;
                           case "Password":
                               eleChild.InnerText = acc.Password.ToString();
                               break;
                       }
                   }
                   xmlDoc.Save("C:\\test\\Accounts.xml");
               }
               else {
                   AccountXML.xmlWriter(acc);
               }
           }
       }

 xmlDelte(Account acc)这个方法有一个Account对象参数,该对象将会被删除

       public static void xmlDelte(Account acc)
       {
           XmlDocument xmlDoc = loadXml();
           XmlNodeList accountList = xmlDoc.SelectSingleNode("Server/Accounts").ChildNodes;
           foreach (XmlNode account in accountList)
           {
               if (acc.Email== account.SelectSingleNode("Email").InnerXml)
               {
                   XmlElement accountElement = (XmlElement)account;
                   //accountElement.RemoveAll();
                   accountElement.ParentNode.RemoveChild(account);
                   //account.ParentNode.RemoveChild(account);
               }
            }
           xmlDoc.Save("C:\\test\\Accounts.xml");
          }
        }

试验验证


我们将在Main方法中进行操作:

    class Program
    {
        static void Main(string[] args)
        {
            Account a = new Account() { Email="Jerry@happy.com",IsAdmin=false, Password="123"};
            AccountXML.xmlWriter(a);
            //read
             List<Account> b = AccountXML.xmlReader();
            a = b[0];
            Console.WriteLine("I am readed by the method AccountXML.xmlReader()");
            Console.WriteLine("Password: "+a.Password);
            Console.WriteLine("Email: "+a.Email);
            Console.WriteLine("IsAdmin: "+a.IsAdmin);
            Console.WriteLine();
            //update
            a.Password = "I am hungry";
            AccountXML.xmlUpdate(a);
            Console.WriteLine("After update object a: ");
            Console.WriteLine("Password: " + a.Password);
            Console.WriteLine("Email: " + a.Email);
            Console.WriteLine("IsAdmin: " + a.IsAdmin);
            Console.WriteLine();
           //Delete
            Console.WriteLine("Before delete object a, the length of List<Account> b is "+b.Count);
            AccountXML.xmlDelte(a);
            b = AccountXML.xmlReader();
            Console.WriteLine("After delete object a, the length of List<Account> b is " + b.Count);

           Console.ReadKey();

        }

    }

 试验结果完全通过,如下所示:

所有代码下载 

Note: 由于只是做test操作,路径信息hardCode写入方法中,实际工作中,可将此信息作为全局参数抽取出来,以便更加方便快捷操作xml。

View Code