c#Xml读写总结

159 篇文章 168 订阅

1、xml文档结构

<?xml version="1.0" encoding="utf-8"?>
<book
  publishTime="2020"
  publishAddress="anhui">
  <title>who am i</title>
  <author>
    <name>xiaoming</name>
  </author>
</book>

1)版本号
在这里插入图片描述
2)文档的编码格式(默认utf-8)
在这里插入图片描述
可通过更改XmlWriterSettings对象的Encoding属性来更改,但是如果XmlWriter的对象创建时使用了TextWriter 类的对象,比如StreamWriter,那么这个Encoding属性将会被StreamWriter的编码格式给覆盖,如下:

var settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.IndentChars = "\n";
            settings.NewLineOnAttributes = true;
            settings.Encoding = Encoding.ASCII;
            settings.WriteEndDocumentOnClose = true;

            StreamWriter sw = new StreamWriter(fileName, false, Encoding.Unicode);
            using (XmlWriter writer = XmlWriter.Create(sw, settings))
            {
                writer.WriteStartDocument();//开头必须是这个
                writer.WriteStartElement("book");//该元素有属性或者元素下面有子元素则使用这个
                writer.WriteAttributeString("publishTime", "2020");//特性
                writer.WriteAttributeString("publishAddress", "anhui");//特性
                writer.WriteElementString("title", "who am i");//元素,并且含有文本
                writer.WriteStartElement("author");//该元素有属性或者元素下面有子元素则适合找个
                writer.WriteElementString("name", "xiaoming");//元素,并且含有文本
                writer.WriteEndElement();//元素结束
                writer.WriteEndDocument();//文档结束
            }
            sw.Close();

因为XmlWriterSettings的Encoding属性是utf-8,但是StreamWriter指定编码格式是unicode,最后生成的xml如下:
在这里插入图片描述
这里的encoding是Utf-16,为什么不是ascii也不是Unicode,是因为unicode也是一种Utf-16,msdn的解释是unicode是 Little-Endian 字节顺序的 UTF-16 格式的编码, Little-Endian 指的是在内存中低位字节存在内存的低地址端。
3)是否缩进元素的值
可通过更改XmlWriterSettings对象的Indent属性来设置,选择true为缩进如下:
在这里插入图片描述
选择false时,不缩进如下:
在这里插入图片描述
从上可以看出,为false时没有选择换行
4)缩进时要使用的字符串

字符串为空时如下:

 var settings = new XmlWriterSettings();
            settings.Indent = true ;
            settings.IndentChars = "";

在这里插入图片描述

 var settings = new XmlWriterSettings();
            settings.Indent = true ;

字符串为两个空格(默认)时如下:
在这里插入图片描述
可以看出使用WriteStartElement方法时就会在原有的字符串空格数量的基础上再加上两个空格。

5)WriteEndDocumentOnClose,调用xmlwriter的close方法时,是否为没有关闭的元素添加结束标记
设置为false时如下:

var settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.NewLineOnAttributes = true;
    settings.Encoding = Encoding.ASCII;
    settings.WriteEndDocumentOnClose = false;

    StreamWriter sw = new StreamWriter(fileName, false, Encoding.Unicode);
    XmlWriter writer = XmlWriter.Create(sw, settings);
    //{
    writer.WriteStartDocument();//开头必须是这个
    writer.WriteStartElement("book4");//该元素有属性或者元素下面有子元素则使用这个
    writer.WriteAttributeString("publishTime", "2020");//特性
    writer.WriteAttributeString("publishAddress", "anhui");//特性
    writer.WriteElementString("title", "who am i");//元素,并且含有文本
    writer.WriteStartElement("author");//该元素有属性或者元素下面有子元素则适合找个
    writer.WriteElementString("name", "xiaoming");//元素,并且含有文本
                                                  //writer.WriteEndElement();//元素结束
                                                  //writer.WriteEndDocument();//文档结束
    writer.Close();

在这里插入图片描述
设置为true时如下:

settings.WriteEndDocumentOnClose = true;

在这里插入图片描述
说明即使没有添加结束元素和文档的代码,只要该属性设置为true,并且调用了xmlwriter的close方法就是可以实现为没有添加结束标记的元素和文档添加结束标记。

6)OmitXmlDeclaration是否省略xml声明
为true时省略
在这里插入图片描述
为false,显示xml声明
xml声明的调用是:

WriteStartDocument()

在这里插入图片描述
xml声明主要是版本信息和编码格式。
注意:这里要注意的是msdn指出 settings.ConformanceLevel = ConformanceLevel.Document 时,不论是否省略都不会忽略xml声明,但实际测试发现即使ConformanceLevel.Document生效,但是OmitXmlDeclaration设置为true时也会省略xml声明;第二个要注意的是,ConformanceLevel属性为ConformanceLevel.Fragment时,调用WriteStartDocument报错,因为此时不允许使用xml声明。

7) settings.CheckCharacters=true;
检查字符是否符合规范,实际测试时,不论这个值是否是true,如果有不符合规范的字符,都会报异常,如下:

writer.WriteStartElement("℃ook4");

上述代码中的温度这个会报错,而不管checkCharacters的属性是不是true
8) settings.CloseOutput=true;调用xmlwriter的close方法时是否也关闭基础流或textwriter
如果设置为true,则不用再调用textwriter的close方法了,否则如果不关闭textwriter的流,下次调用就会出错。
9)NewLineOnAttributes
指示是否在新行上写入属性
当为false时如下:
在这里插入图片描述
当为true时如下:
在这里插入图片描述

2、XmlWriter

 class XmlHelp
    {
        public void WriterXml(string fileName)
        {
            var settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.NewLineOnAttributes = true;
            settings.Encoding = Encoding.UTF8;
            settings.WriteEndDocumentOnClose = true;

            StreamWriter sw = File.CreateText(fileName );
            using (XmlWriter writer = XmlWriter.Create(sw, settings)) 
            {
                writer.WriteStartDocument();//开头必须是这个
                writer.WriteStartElement("book");//该元素有属性或者元素下面有子元素则使用这个
                writer.WriteAttributeString("publishTime","2020");//特性
                writer.WriteAttributeString("publishAddress", "anhui");//特性
                writer.WriteElementString("title", "who am i");//元素,并且含有文本
                writer.WriteStartElement("author");//该元素有属性或者元素下面有子元素则适合找个
                writer.WriteElementString("name", "xiaoming");//元素,并且含有文本
                writer.WriteEndElement();//元素结束
                writer.WriteEndDocument();//文档结束
            }

        }
    }

调用:

XmlHelp xmlHelp = new XmlHelp();
            xmlHelp. WriterXml("1.xml");

2)WriteChars

 writer.WriteElementString("name", "xiaoming");//元素,并且含有文本
            string str1 = "123";
            char[] array = Encoding.Unicode.GetChars (Encoding .Unicode .GetBytes (str1));
            writer.WriteChars(array,0, array.Length );
            writer.WriteEndElement();//元素结束
            writer.WriteEndDocument();//文档结束
            writer.Close();

输出的结果:
在这里插入图片描述
从上面可以看出,123也被写入xml

3)WriteComment
在这里插入图片描述
输出:
在这里插入图片描述
可以看出注释是另起一行了。
4)其他的一些方法

 string str1 = "我是注释";
            writer.WriteComment (str1);
            writer.WriteString("WriteString");
            writer.WriteCData("WriteCData");
            writer.WriteRaw("WriteCData");
            writer.WriteString("\r\n");
            byte[] bytes = Encoding.Unicode.GetBytes("123");
            writer.WriteBase64(bytes, 0, bytes.Length );
            writer.WriteString("\r\n");
            writer.WriteBinHex(bytes,0, bytes.Length );
            writer.WriteString("\r\n");
            writer.WriteEntityRef("WriteEntityRef");
            writer.WriteName("name");
            writer.WriteNmToken("WriteNmToken");
            writer.WriteWhitespace("               ");
            writer.WriteValue(new int[] { 1,2,3,4});
            writer.WriteEndElement();//元素结束
            writer.WriteEndDocument();//文档结束
            writer.Close();

在这里插入图片描述
要注意的是WriteWhitespace写入空格,而且只能传入空格。

3、xmlReader

public void ReadXml(string xmlFileName)
        {
            var setting = new XmlReaderSettings();
            setting.DtdProcessing = DtdProcessing.Parse;
            Stream stream = File.OpenRead(xmlFileName);
            XmlReader read = XmlReader.Create(stream, setting);
            while (read.Read())
            {
                var tpStr = read.NodeType.ToString();
                var value = read.Value;
                Console.WriteLine($"type:{tpStr},value:{value}");
            }
            }

调用:

  xmlHelp.ReadXml ("1.xml");

输出:

type:XmlDeclaration,valueversion="1.0" encoding="utf-16"
type:Whitespace,value:

type:Element,value:
type:Whitespace,value:
  
type:Element,value:
type:Text,value:who am i
type:EndElement,value:
type:Whitespace,value:
  
type:Element,value:
type:Whitespace,value:
    
type:Element,value:
type:Text,value:xiaoming
type:EndElement,value:
type:Whitespace,value:
  
type:EndElement,value:
type:Whitespace,value:

type:EndElement,value:

由于上面读取的文件如下:
在这里插入图片描述
从输出可以看出以下几点:
1)看出第一行指定了xml节点的类型是XmlDeclaration,然后read读取器的value属性也能输出xml声明;
2)要换行的时候找到的xml节点类型都是Whitespace,然后read读取器的value属性是"\n";
3)找到元素节点的时候,节点类型是Element,然后read读取器的value属性是"";
4)元素的属性是不能直接通过read.value属性获取的;
5)找到Text文本的时候,节点类型是text
6)结束元素的时候,找到的节点类型是EndElement,readf读取器的value属性也是"";

另外xmlReader还可以这样使用:

 while (!read.EOF)//定位下一个节点
            {
                read.MoveToContent();

                var tpStr = read.NodeType.ToString();
                var value = read.Value;
                Console.WriteLine($"type:{tpStr},value:{value}");
                read.Read();
            }

输出:

type:Element,value:
type:Element,value:
type:Text,value:who am i
type:EndElement,value:
type:Element,value:
type:Element,value:
type:Text,value:xiaoming
type:EndElement,value:
type:EndElement,value:
type:EndElement,value:

从上可以看出使用 read.MoveToContent()可以忽略掉Whitespace以及XmlDeclaration这样的节点,效率更高了。

4、查找特性

 while (!read.EOF)//定位下一个节点
            {
                if (read.MoveToContent() == XmlNodeType.Element)
                {
                    int count = read.AttributeCount;
                    for (int i = 0; i < count; i++)
                    {
                        string attrriStr = read.GetAttribute(i);
                        Console.WriteLine($"Attribute:{attrriStr}");
                    }
                }
                read.Read();
            }

输出:

Attribute:2020
Attribute:anhui

成功的将元素节点book4的两个属性输出了。

5、XmlDocument
在这里插入图片描述

1、读取xml

  public void ReadXmlByXmlDocument(string xmlFileName)
    {
        using (FileStream steam = File.OpenRead(xmlFileName))
        {
            var doc = new XmlDocument();
            doc.Load(steam);
            XmlNodeList xmlNodeList = doc.GetElementsByTagName("author");
            foreach (XmlNode item in xmlNodeList)
            {
                Console.WriteLine($"OuterXml {item.OuterXml}");
                Console.WriteLine($"InnerXml {item.InnerXml }");
                Console.WriteLine($"PreviousSibling .OuterXml {item.PreviousSibling.OuterXml  }");
                Console.WriteLine($"NextSibling .OuterXml {item.NextSibling.OuterXml  }");
                Console.WriteLine($"FirstChild .OuterXml {item.FirstChild.OuterXml  }");
                Console.WriteLine($"LastChild .OuterXml {item.LastChild.OuterXml  }");
                Console.WriteLine($"ParentNode .OuterXml {item.ParentNode.OuterXml  }");
                Console.WriteLine($"item.InnerText{item.InnerText  }");
            }
        }
    }

输出:

OuterXml <author><name>xiaoming</name><press>qinghuadaxue</press></author>
InnerXml <name>xiaoming</name><press>qinghuadaxue</press>
PreviousSibling .OuterXml <title>who am i</title>
NextSibling .OuterXml <time>1997</time>
FirstChild .OuterXml <name>xiaoming</name>
LastChild .OuterXml <press>qinghuadaxue</press>
ParentNode .OuterXml <book4 publishTime="2020" publishAddress="anhui"><title>who am i</title><author><name>xiaoming</name><press>qinghuadaxue</press></author><time>1997</time></book4>
item.InnerTextxiaomingqinghuadaxue

1)OuterXml
输出当前节点以及子节点的标记
2)InnerXml
输出子节点的标记
3)PreviousSibling
输出前一个节点的标记
4)NextSibling
输出下一个节点的标记
5)FirstChild
输出第一个子节点的标记
6)LastChild
输出最后一个子节点的标记
7)ParentNode
输出父节点以及父节点的所有子节点的标记
8)InnerText
输出所有子节点的文本连接起来的字符串。
2、更新xml(xmldocument的作用之一就是更改已经存在的xml文件的内容,但是xmlwriter无法实现)

   public void UpdateXmlByXmlDocument(string xmlFileName)
        {
            var doc = new XmlDocument();
            using (FileStream steam = File.OpenRead(xmlFileName))
            {

                doc.Load(steam);
                XmlElement person = doc.CreateElement("person");//创建元素节点
                person.SetAttribute("test2", "2");//设置元素属性
                XmlElement person2 = doc.CreateElement("person2");//创建元素节点
                person2.InnerText = "test3";//给元素创建文本
                person.AppendChild(person2);
                doc.DocumentElement.AppendChild(person);
            }
            doc.Save(xmlFileName);
        }

输出结果:

<?xml version="1.0" encoding="utf-16"?>
<book4 publishTime="2020" publishAddress="anhui">
  <title>who am i</title>
  <author>
    <name>xiaoming</name>
    <press>qinghuadaxue</press>
  </author>
  <time>1997</time>
  <person test2="2">
    <person2>test3</person2>
  </person>
</book4>

6、xpath

public void SimpleNavigate(string xmlFileName)
        {
            var doc = new XPathDocument(xmlFileName);
            XPathNavigator nav = doc.CreateNavigator();
            XPathNodeIterator iterator = nav.Select("/book4/author");

            while (iterator.MoveNext())
            {
                XPathNodeIterator subIterator = iterator.Current.SelectDescendants(XPathNodeType.Element, false);
                while (subIterator.MoveNext ())
                {
                    Console.WriteLine(subIterator.Current.Value);
                }
            }
        }

输出:

xiaoming
qinghuadaxue

7、序列化对象
1)把对象序列化到xml文件中

 public enum Gender
    {,}
    struct Country
    {
        public string China { get; set; }
        public string American { get; set; }
    }

    public class People
    {
        public int Age { get; set; }
    }
   public class Product
    {
        public int Discount { get; set; }
        public string Name { get; set; } = "";
        public People people = new People() { Age = 100 };
        public Gender gender=Gender.;
        Country country;

    }
  Product product = new Product();
        string fileName = "1.xml";
        StreamWriter sw = new StreamWriter(fileName);
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(Product));
        xmlSerializer.Serialize(sw, product);
        sw.Flush();
        sw.Close();

这里要注意的是字符串类型Name变量的初始值为"“时,Name元素的显示如下:在这里插入图片描述
如果Name初始值为Null,则Name不显示,如下:
在这里插入图片描述
所以如果想让字符串类型的变量显示的比较全的话,最好给字符串变量赋予一个初始值,这个值也不要是空”"。

2)把xml文件反序列化为对象

   StreamReader sr = new StreamReader(fileName);
            XmlSerializer xmlDeserialize = new XmlSerializer(typeof(Product));
            Product product1 = xmlDeserialize.Deserialize(sr) as Product;
            sr.Close();

3)序列化的对象中有数组成员,并且这个数组存储了基类和派生类,如下:
定义:

 public class People
    {
        public int Age { get; set; }
    }

    public class SubPeople : People
    {
        public int Height { get; set; }
    }
  public class Product
    {
        public People[] peopleArray { get; set; }
    }

调用:

 Product product = new Product();
            People people = new People() { Age = 200 };
            People subPeople = new SubPeople();
            People[] peoples = { people, subPeople };
            product.peopleArray   = peoples;
           

            string fileName = "1.xml";
            StreamWriter sw = new StreamWriter(fileName);
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Product));
            xmlSerializer.Serialize(sw, product);
            sw.Flush();
            sw.Close();

输出:
报错,如下:
在这里插入图片描述
说明类型不对,要解决数组中能否序列化基类和派生类可以这样做,如下:

 public class Product
    {
        [XmlArrayItem("people", typeof(People)),
         XmlArrayItem("subPeople", typeof(SubPeople))]
        public People[] peopleArray { get; set; }
    }

输出:

<?xml version="1.0" encoding="utf-8"?>
<Product xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <peopleArray>
    <people>
      <Age>200</Age>
    </people>
    <subPeople>
      <Age>0</Age>
      <Height>0</Height>
    </subPeople>
  </peopleArray>
</Product>

4)针对不能为数组类型手动增加特性的情况(看不到源代码的时候)
定义:

  public class Product
    {
        public int Count { get; set; } = 123;
        public People[] peopleArray { get; set; }
    }
 private static XmlAttributeOverrides GetProductXmlAttributes()
        {
            var attributes = new XmlAttributes();
            attributes.XmlArrayItems.Add(new XmlArrayItemAttribute ("people", typeof(People)));
            attributes.XmlArrayItems.Add(new XmlArrayItemAttribute("subPeople", typeof(SubPeople)));
            var overrides = new XmlAttributeOverrides();
            overrides.Add(typeof(Product), "peopleArray", attributes);
                return overrides;

        }

调用:

Product product = new Product();
            People people = new People() { Age = 200 };
            People subPeople = new SubPeople();
            People[] peoples = { people, subPeople };
            product.peopleArray = peoples;


            string fileName = "1.xml";
            StreamWriter sw = new StreamWriter(fileName);
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Product), GetProductXmlAttributes());
            xmlSerializer.Serialize(sw, product);
            sw.Flush();
            sw.Close();
            //XmlHelp xmlHelp  = new XmlHelp();
            //xmlHelp.WriterXml("1.xml");



            StreamReader sr = new StreamReader(fileName);
            XmlSerializer xmlDeserialize = new XmlSerializer(typeof(Product), GetProductXmlAttributes());
            Product product1 = xmlDeserialize.Deserialize(sr) as Product;
            sr.Close();

8、Linq to xml

 XmlHelp xmlHelp = new XmlHelp();
            xmlHelp.WriterXml("1.xml");

            XDocument doc = XDocument.Load("1.xml");
            var e1 = doc.Descendants();
            var element = doc.Descendants().Where(item => item.Name == "author").Select(subitem => subitem.Value).FirstOrDefault();

其中xml文档结构为:

<?xml version="1.0" encoding="utf-16"?>
<book4 publishTime="2020" publishAddress="anhui">
  <title>who am i</title>
  <author>
    <name>xiaoming</name>
    <press>qinghuadaxue</press>
  </author>
  <time>1997</time>
</book4>

输出的element的值为:

xiaomingqinghuadaxue
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c#上位机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值