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