代码改变世界

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

  立雪三尺  阅读(1744)  评论(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。

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
View Code
点击右上角即可分享
微信分享提示