C# - XML讀寫與序列化

綠龍術士發表於2018-04-09

· XML資料格式

· 我們可以使用XMLDocument類在文件物件模型(DOM)層次結構內導航

· 也可以使用XMLReaderXMLWriter。使用XML更復雜,但可以讀取更大的檔案。使用XMLDocument把文件全部載入進了記憶體中,使用XMLReader可以逐個節點讀取。

· 另一個使用XML的方式是System.Xml.Serialization,把.NET物件序列化為XML,也可以把XML反序列化為.NET物件。

· 查詢XML內容時,可以使用XML標準XPathLinq to Xml

· 對於WCFXML可以壓縮為二進位制格式。JSON也可以壓縮為二進位制格式(BSON) .

· 我們可以使用WSDL描述XML資料,使用Swagger描述JSON資料。

· XmlReader,XMLDocument和XPathNavigator類

· XmlReaderXmlWriter類提供了讀寫大型XML文件的快速方式。

· 常見的遍歷文件的方法有Read()方法進入下一個節點。然後驗證該節點是否有值(HasValue()),或者該節點是否有特性(HasAttributes())XmlReader還可以讀取強型別的資料,它有幾個方法如:ReadElementContentAsDouble()ReadElementContentAsString()

讀取文字內容:

            using (XmlReader reader = XmlReader.Create("books.xml"))
            {
                while(reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Text)
                    {
                        Console.WriteLine(reader.Value);
                    }
                }
            }

讀取節點資訊:

            using (XmlReader reader = XmlReader.Create(bookFile))
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        for (int i = 0; i < reader.AttributeCount; i++)
                        {
                            Console.WriteLine(reader.GetAttribute(i));
                        }

                    }
                }
            }

寫入XmlWriter寫入一個流:

            var setting = new XmlWriterSettings()
            {
                Indent = true,//縮排
                IndentChars = "  ",//縮排字元
                NewLineOnAttributes = false,
                Encoding = Encoding.UTF8,
                WriteEndDocumentOnClose = true,
            };

            StreamWriter stream = File.CreateText(newXml);//開啟一個寫入流
            using (XmlWriter writer = XmlWriter.Create(stream, setting))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("book");
                writer.WriteAttributeString("gener", "Mystery");
                writer.WriteAttributeString("publicationdate", "2001");
                writer.WriteAttributeString("ISBN", "123456789");
                writer.WriteElementString("title", "Case of missing Cookie");
                writer.WriteStartElement("author");
                writer.WriteElementString("name", "Cookie Monster");
                writer.WriteEndElement();
                writer.WriteElementString("price", "9.99");
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }


· XmlDocument類用於在.NET中讀寫DOM類。與XmlReaderXmlWriter不同的是XmlDocument具有讀寫的功能,並可以隨機訪問DOM樹。常見的遍歷方法有GetElementByTagName()獲取指定元素的列表,然後呼叫子集的OuterXml,InnerXml,NextSibling,PreviousSibling等屬性。

遍歷層次結構:

            using (FileStream stream = File.OpenRead(bookFile))
            {
                var doc = new XmlDocument();
                doc.Load(stream);
                var nodeList = doc.GetElementsByTagName("author");
                foreach (XmlNode item in nodeList)
                {
                    //OuterXml包含此節點及子節點
                    Console.WriteLine($"OuterXml:{item.OuterXml}");
                    //InnerXml包含子節點
                    Console.WriteLine($"InnerXml:{item.InnerXml}");
                    Console.WriteLine($"兄弟節點(下一個節點)的OuterXml:{item.NextSibling.OuterXml}");
                    Console.WriteLine($"兄弟節點(上一個節點)的OuterXml:{item.PreviousSibling.OuterXml}");
                    Console.WriteLine($"父節點的OuterXml:{item.ParentNode.OuterXml}");
                    break;
                }
                Console.Read();
            }

XMLDocument寫入檔案:

            var doc = new XmlDocument();
            using (FileStream stream = File.OpenRead(bookFile))
            {
                doc.Load(stream);
            }
            var book = doc.CreateElement("book");
            book.SetAttribute("genre", "MyStery");
            book.SetAttribute("publicationdate", "2001");
            book.SetAttribute("ISBN", "123456789");
            var title = doc.CreateElement("title");
            title.InnerText = "Case of Missing Cookie";
            book.AppendChild(title);//將title節點新增到book子節點的末尾
            var author = doc.CreateElement("author");
            book.AppendChild(author);//將author節點新增到book子節點的末尾
            var name = doc.CreateElement("name");
            name.InnerText = "Cookie Monster";
            author.AppendChild(name);
            var price = doc.CreateElement("price");
            price.InnerText = "9.99";
            book.AppendChild(price);

            doc.DocumentElement.AppendChild(book);//將book節點新增到根節點(bookStore)的子節點的末尾
            var setting = new XmlWriterSettings()
            {
                Indent = true,
                IndentChars = "\t",
                NewLineChars = Environment.NewLine,
            };
            using (StreamWriter stream = File.CreateText(newbook2))
            {
                //建立或開啟一個寫入流
                using (XmlWriter writer = XmlWriter.Create(stream, setting))
                {
                    //建立一個寫入器,並將所有內容寫入進去
                    doc.WriteContentTo(writer);
                }
                var list = doc.GetElementsByTagName("title");
                foreach (XmlNode item in list)
                {
                    Console.WriteLine(item.OuterXml);
                }
                Console.Read();
            }

· XPathNavigator也可以讀寫XML文件,特點是可以通過XPath語句訪問到指定元素。要注意的是,只用通過XMLDocument建立的物件才可以修改檔案,通過XMLPathDocument建立的物件是隻讀的。。

XPathNavigator讀取元素:

            var doc = new XPathDocument(bookFile);

            var xPathNavigator = doc.CreateNavigator();
            //選擇和設定一組重複節點
            var iter = xPathNavigator.Select("/bookstore/book[@genre='novel']");

            while(iter.MoveNext())
            {
                var newiter = iter.Current.SelectDescendants(XPathNodeType.Element, false);
                while(newiter.MoveNext())
                {
                    Console.WriteLine($"{newiter.Current.Name} {newiter.Current.Value}");
                }
            }

XPathNavigator修改元素:

            //注意:只有XmlDocument才能修改XML元素!
            XmlDocument doc = new XmlDocument();
            doc.Load(bookFile);
            XPathNavigator xPathNavigator = doc.CreateNavigator();

            //選擇和設定一組重複節點
            var iter = xPathNavigator.Select("/bookstore/book[@genre='novel']");

            while (iter.MoveNext())
            {
                var iter_items = iter.Current.SelectDescendants(XPathNodeType.Element, false);
                while (iter_items.MoveNext())
                {
                    var value = iter_items.Current.Value;
                    iter_items.Current.SetValue("100");
                }
             }
            doc.Save("book2.xml");

· XML序列化

· .NET Framework為序列化提供了兩個名稱空間:System.Xml.SerializationSystem.Xml.XmlSerializer。它包含的類可用於把物件序列化為Xml文件或者流。這也就表示把物件的公共屬性和欄位轉換為Xml元素或屬性。

· 我們可以在POCO的屬性上新增XmlElement元素,來定義輸出XML的名稱,名稱空間,型別等。如:ElementName設定XML元素的名稱,Namespace設定名稱空間的名稱,Order設定順序

· XmlAttribute可以將POCO的屬性設定為XML的屬性,並且可以設定XML屬性的名稱,名稱空間等。

序列化一個物件:

            Product product = new Product()
            {
                CategoryID = 1,
                Discontinued = true,
                Discount = 15,
                ProductID = 1,
                ProductName = "戴爾膝上型電腦",
                QuantityPerUnit = "6",
                ReorderLevel = 1,
                SupplierID = 1,
                UnitPrice = 4000,
                UnitsInStock = 10,
                UnitsOnOrder = 0
            };
            //開啟一個檔案流
            var stream = File.OpenWrite("product.xml");
            //向檔案流中寫入字元
            using (TextWriter writer = new StreamWriter(stream))
            {
                //建立一個序列化例項物件
                XmlSerializer serializer = new XmlSerializer(typeof(Product));
                serializer.Serialize(writer, product);//將物件寫入到檔案流中
            }
            Console.Read();

反序列化一個物件:

            Product product;
            //開啟一個檔案流
            using (var stream = new FileStream("product.xml", FileMode.Open))
            {
                var serializer = new XmlSerializer(typeof(Product));
                product = (Product)serializer.Deserialize(stream);
            }

相關文章