【C# XML】XmlDocument 類


原文地址:https://zhuanlan.zhihu.com/p/337698648

 

 

XML 節點類型

當將 XML 文檔作為節點樹讀入內存時,這些節點的節點類型在創建節點時確定。 XML 文檔對象模型 (DOM) 具有多種節點類型,這些類型由萬維網聯合會 (W3C) 確定並在 1.1.1 節“The DOM Structure Model”中列出。 下表列出了節點類型、分配給該節點類型的對象以及每種節點類型的簡短說明。

DOM 節點類型

object

說明

Document

XmlDocument 類

樹中所有節點的容器。 它也稱作文檔根,文檔根並非總是與根元素相同。

DocumentFragment

XmlDocumentFragment 類

包含一個或多個不帶任何樹結構的節點的臨時袋。

DocumentType

XmlDocumentType 類

表示 <!DOCTYPE…> 節點。

EntityReference

XmlEntityReference 類

表示非擴展的實體引用文本。

Element

XmlElement 類

表示元素節點。

Attr

XmlAttribute 類

為元素的屬性。

ProcessingInstruction

XmlProcessingInstruction 類

為處理指令節點。

Comment

XmlComment 類

注釋節點。

Text

XmlText 類

屬於某個元素或屬性的文本。

CDATASection

XmlCDataSection 類

表示 CDATA。

Entity

XmlEntity 類

表示 XML 文檔(來自內部文檔類型定義 (DTD) 子集或來自外部 DTD 和參數實體)中的 <!ENTITY…> 聲明。

Notation

XmlNotation 類

表示 DTD 中聲明的表示法。

盡管屬性 (attr) 在 W3C DOM 級別 1 的 1.2 節“Fundamental Interfaces”中作為節點列出,但不能將其視為任何元素節點的子級。

下表顯示了 W3C 未定義的其他節點類型,但這些類型可作為 XmlNodeType 枚舉在 Microsoft .NET Framework 對象模型中使用。 因此,這些節點類型不存在匹配的 DOM 節點類型列。

節點類型

說明

XmlDeclaration

表示聲明節點 <?xml version="1.0"…>。

XmlSignificantWhitespace

表示有效空白(混合內容中的空白)。

XmlWhitespace

表示元素內容中的空白。

EndElement

XmlReader 到達元素的末尾時返回。

示例 XML: </item>

有關更多信息,請參見 XmlNodeType 枚舉

EndEntity

XmlReader 由於調用 ResolveEntity 而到達實體替換的末尾時返回。 有關更多信息,請參見 XmlNodeType 枚舉

XmlDocument 類的方法和屬性

  1. XmlDocument 類的一些常用的屬性
屬性 描述
XmlAttributeCollection Attributes { get; } 獲取當前節點的所有屬性引用對象集合
XmlNodeList ChildNodes { get; } 獲取子級節點集合
XmlElement DocumentElement { get; } 獲取文檔的根節點
XmlDocumentType DocumentType { get; } 獲取XML文檔類型定義
XmlNodeType NodeType { get; } 獲取當前節點的類型
XmlDocument OwnerDocument { get; } 獲取當前節點所屬的 XmlDocument 對象
XmlNode ParentNode { get; } 獲取父節點(針對可以擁有父級的節點)
string BaseURI { get; } 獲取文檔的地址
string InnerText { get; set;} 獲取或設置當前節點和子級的文本
string InnerXml { get; set; } 獲取或設置子級節點的標簽和文本
string LocalName { get; } 獲取節點本地名稱
string Name { get; } 獲取節點限定名稱
bool IsReadOnly { get; } 是否只讀
bool PreserveWhitespace { get; set; } 獲取或設置元素內容是否保留空白區域
XmlNameTable NameTable { get; } 獲取關聯的 XmlNameTable
IXmlSchemaInfo SchemaInfo { get; } 返回節點的后架構驗證信息集 (PSVI)
XmlSchemaSet Schemas { get; set; } 獲取或設置與此 XmlDocument 關聯的XmlSchemaSet 對象
XmlNode NextSibling { get; } 獲取下一個節點(XmlNode)
XmlNode PreviousSibling { get; } 獲取上一個節點(XmlNode)
XmlNode PreviousText { get; } 獲取該節點之前的文本節點(XmlNode)
XmlNode LastChild { get; } 獲取該節點的最后一個子節點(XmlNode)
XmlNode FirstChild { get; } 獲取節點的第一個子級(XmlNode)
XmlElement Item[string name] { get; } 獲取具有指定Name的第一個子元素 (XmlNode)
string OuterXml { get; } 獲取當前節點和子級的標簽和文本(XmlNode)
string Prefix { get; set; } 獲取或設置該節點的命名空間前綴(XmlNode)
string Value { get; set; } 獲取或設置節點的值(XmlNode)
string NamespaceURI { get; } 獲取該節點的命名空間 URI(XmlNode)
bool HasChildNodes { get; } 判斷該節點下是否有子節點(XmlNode)

2. XmlDocument 類的一些常用的方法

方法 描述
XmlElement CreateElement (string name); 創建一個新節點
XmlAttribute CreateAttribute (string name); 創建指定名稱的屬性
void SetAttribute(string attribute ,string value); 為指定節點的新建屬性並賦值
mlNode AppendChild (XmlNode newChild); 為指定節點末尾添加子節點(XmlNode)
XmlAttribute SetAttributeNode(XmlAttribute newAttr); 指定節點添加指定的屬性
XmlElement GetElementById (string elementId); 獲取具有指定ID的XmlElement
XmlNodeList GetElementsByTagName (string name); 返回一個 XmlNodeList,它包含與指定Name匹配的所有節點的列表,特殊值“*”匹配所有標記
XmlNode ImportNode (XmlNode node, bool deep); 將節點從另一個文檔導入到當前文檔
XmlNode CreateNode (string nodeType, string name, string namespace); 創建一個節點
XmlNode InsertAfter (XmlNode newChild, XmlNode refChild); 將指定的節點緊接着插入指定的引用節點之后(XmlNode)
XmlNode InsertBefore (XmlNode newChild, XmlNode refChild); 將指定的節點緊接着插入指定的引用節點之前(XmlNode)
void Load (string filename); 從指定的地址加載 XML 文檔
void LoadXml (string xml); 從指定的字符串加載 XML 文檔
XmlNode PrependChild (XmlNode newChild); 指定的節點添加到該節點的子節點列表的開頭(XmlNode)
XmlNode SelectSingleNode (string xpath); 選擇一個節點
XmlNodeList SelectNodes (string xpath); 獲取同名同級節點集合
void RemoveAll (); 移除當前節點的所有子節點和/或屬性(XmlNode)
XmlNode RemoveChild (XmlNode oldChild); 移除指定的子節點(XmlNode)
XmlNode ReplaceChild (XmlNode newChild, XmlNode oldChild); 用新子節點替換舊子節點(XmlNode)
void Save (string filename); 保存XML文件,如果存在指定文件,則此方法會覆蓋它

關於查詢,可以簡單了解一下XPath表達式:

表達式 描述
nodename 選取此節點的所有子節點
/ 從根節點選取
// 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置
. 選取當前節點
.. 選取當前節點的父節點
@ 選取屬性

代碼演示

示例XML文檔內容如下:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE note SYSTEM "Note.dtd"[]> <note> <ID id1="111" id2="222"/> <name>張三</name> <jobs> <type>搬磚</type> <time>1h</time> </jobs> <jobs> <type>伐木</type> <time>1h</time> </jobs> <sex> <man>男</man> <woman>女</woman> </sex> </note>

 

using System;
using System.Xml;

namespace XML操作
{
    class Program
    {
        static void Main(string[] args)
        {
            XMLTest();
            XMLTest2();
            Console.ReadKey();
        }
        //先封裝一個簡單的輸出方法方便驗證結果
        /// <summary>
        /// 一個簡單輸出方法
        /// </summary>
        static void C(string str,object obj)
        {
            Console.WriteLine(" {0}: {1}" ,str, obj);
            Console.WriteLine(" ------------------------------");
        }

        //定義兩個文檔地址
        static string filePath = @"C:\Users\Administrator\Desktop\Temp\test.xml";   
        static string filePath2 = @"C:\Users\Administrator\Desktop\Temp\test2.xml";  
        //定義兩個 XML 對象
        static XmlDocument xml; 
        static XmlDocument xml2;
        //定義兩個常用的節點
        static XmlNode IDnote;
        static XmlNode jobsnote;

        /// <summary>
        /// XML屬性測試
        /// </summary>
       static void XMLTest()
        {
            //構造函數
            xml = new XmlDocument();

            //如果 XML 文檔中存在注釋,讀取時會報錯
            //可以通過 XmlReaderSettings ,XmlReader 組合設置即可
            //文檔讀取完畢后,要關閉 XmlReader
            XmlReaderSettings settings = new XmlReaderSettings();

            //設置忽略注釋
            settings.IgnoreComments = true;

            //通過 XmlReader 設置規則
            XmlReader reader = XmlReader.Create(filePath, settings);

            //讀取 XmlReader 中緩存的 XML

            xml.Load(reader);

            //關閉 XmlReader
            reader.Close();

            //選擇第一個按標簽匹配到的節點,節點需要從根節點開始一層一層到當前節點標簽
            IDnote = xml.SelectSingleNode("/note/ID");
            jobsnote = xml.SelectSingleNode("/note/jobs");

            Console.WriteLine("\n ------------------------------\n");

            Console.WriteLine(" 1.獲取 當前 節點的所有屬性引用對象集合");
            //不包含子級的屬性
            XmlAttributeCollection attributes = IDnote.Attributes;
            //遍歷出來的item必須指定類型(拆箱),否則默認為boject類型
            foreach (XmlNode i in attributes) C("Attributes", i.Value);

            Console.WriteLine(" 通過 item 的方式直接獲取單個屬性的引用對象");
            //需要通過 item[] 的方式定位到具體屬性名
            C("Attributes[id1]", IDnote.Attributes["id1"].Value);
            
            Console.WriteLine(" 2.獲取 文檔的地址");
            string URI = xml.BaseURI;
            C("BaseURI", URI);

            Console.WriteLine(" 3.獲取 當前 節點本地名稱");
            string localName = jobsnote.LocalName;
            C("LocalName", localName);

            Console.WriteLine(" 4.獲取 當前節點 限定名稱");
            string name = jobsnote.Name;
            C("Name", name);
        }
    }
}
View Code

 

運行結果:

 

 

            Console.WriteLine(" 5.獲取 當前和子級 的標簽和文本(XmlNode)");
            string outerXml = jobsnote.OuterXml;
            C("OuterXml", outerXml);

            Console.WriteLine(" 6.獲取或設置 當前和子級 的文本");
            string innerText = jobsnote.InnerText;
            C("InnerText", innerText);

            Console.WriteLine(" 7.獲取或設置 子級 節點的標簽和文本");
            //只能獲取子節點,不包含當前節點
            string innerXml = jobsnote.InnerXml;
            C("InnerXml", innerXml);

            Console.WriteLine(" 8.獲取 XML文檔類型定義");
            XmlNode documentType = xml.DocumentType;
            C("DocumentType", documentType.OuterXml);

            Console.WriteLine(" 9.獲取 子級 節點集合");
            //只能獲取子節點,不包含當前節點
            XmlNodeList childNodes = jobsnote.ChildNodes;
            //可以通過 XmlNodeList.Item(index) 方法索引獲得單個節點
            string childNodesItem = childNodes.Item(0).LocalName;
            //也可以遍歷列表
            foreach (XmlNode i in childNodes) C(" ChildNodes", i.LocalName);

            Console.WriteLine(" 10.獲取 文檔的 根 節點");
            //根節點是唯一的
            XmlNode documentElement = xml.DocumentElement;
            C("DocumentElement", documentElement.LocalName);

            Console.WriteLine(" 11.獲取 當前文檔的 XmlImplementation 對象");
            XmlImplementation xmlImplementation = xml.Implementation;
            Console.WriteLine("\n ------------------------------\n");
View Code

 

運行結果:

 

 

            Console.WriteLine(" 12.判斷 是否只讀");
            bool isRead = xml.IsReadOnly;
            C("IIsReadOnly" , isRead);

            Console.WriteLine(" 13.獲取或設置 元素內容是否保留空白區域");
            //經過試驗,設置為 true 會將每一行開頭和結尾的空白以及換行符給去掉
            //相反,false 會保留開頭和結尾的處的空白和換行符
            //??為何呢??
            bool preserveWhitespace = xml.PreserveWhitespace;
            C("PreserveWhitespace", preserveWhitespace);

            Console.WriteLine(" 14.獲取 當前節點 的類型");
            XmlNodeType nodeType = jobsnote.NodeType;
            XmlNodeType nodeType2 = xml.NodeType;
            C("1.NodeType", nodeType);
            C("2.NodeType", nodeType2);

            Console.WriteLine(" 15.獲取 當前節點 所屬的 XmlDocument 對象");
            XmlDocument ownerDocument = jobsnote.OwnerDocument;
            C("OwnerDocument" , ownerDocument);

            Console.WriteLine(" 16.獲取 父 節點");
            //針對可以擁有父級的節點
            XmlNode parentNode = jobsnote.ParentNode;
            C("ParentNode" , parentNode.LocalName);

            Console.WriteLine(" 17.獲取 下一個節點(XmlNode)");
            //注意:
            //1.下一個節點必須是當前節點的同級節點,否則會返回null
            //2.如果存在多個標志相同的節點,則默認為第一個
            //下面代碼會報錯,因為不存在和根節點同級的節點,版本聲明不屬於節點
            //XmlNode next = xml.DocumentElement.NextSibling; 
            XmlNode nextSibling = jobsnote.NextSibling;
            C("NextSibling" , nextSibling.LocalName);

            Console.WriteLine(" 18.獲取 上一個節點(XmlNode)");
            //注意:內容同上
            XmlNode previousSibling = jobsnote.PreviousSibling;
            C("PreviousSibling" , previousSibling.LocalName);

 

運行結果:

 

 

    Console.WriteLine(" 19.獲取 當前 節點之前的文本節點(XmlNode)");
            //??不知為何返回null??
            //請求高人指點
            XmlNode previousText = jobsnote.PreviousText;
            //C("PreviousText" , previousText.InnerXml); 
            Console.WriteLine("\n ------------------------------\n");

            Console.WriteLine(" 20.獲取 當前 節點的 最后子級(XmlNode)");
            XmlNode lastChild = jobsnote.LastChild;
            C("LastChild" , lastChild.LocalName);

            Console.WriteLine(" 21.獲取 當前 節點的 首位子級(XmlNode)");
            XmlNode firstChild = jobsnote.FirstChild;
            C("FirstChild" , firstChild.LocalName);

            Console.WriteLine(" 22.獲取 具有指定 Name 的第一個子元素 (XmlNode)");
            XmlNode item = documentElement["jobs"];
            C("item" , item.LocalName);

            Console.WriteLine(" 23.獲取或設置節點的值(XmlNode)");
            //注意:
            //這里想要獲得Value的值,必須詳細定位到哪個屬性,需要調用Attributes["屬性名"]
            string value = IDnote.Attributes["id2"].Value;
            C("Value", value);

            Console.WriteLine(" 24.獲取該節點的命名空間 URI(XmlNode)");
            string namespaceURI = xml.NamespaceURI;
            C("NamespaceURI", namespaceURI);

            Console.WriteLine(" 25.判斷該節點下是否有子節點(XmlNode)");
            bool hasChildNodes = xml.HasChildNodes;
            C("HasChildNodes", hasChildNodes);

 

運行結果:

 

 

    static void XMLTest2()
        {
            //構造函數
            xml = new XmlDocument();

            //如果 XML 文檔中存在注釋,讀取時會報錯
            //可以通過 XmlReaderSettings ,XmlReader 組合設置即可
            //文檔讀取完畢后,要關閉 XmlReader
            XmlReaderSettings settings = new XmlReaderSettings();

            //設置忽略注釋
            settings.IgnoreComments = true;

            //通過 XmlReader 設置規則
            XmlReader reader = XmlReader.Create(filePath, settings);

            //讀取 XmlReader 中緩存的 XML

            xml.Load(reader);

            //關閉 XmlReader
            reader.Close();

            //獲取根節點
            XmlElement rootElement = xml.DocumentElement;

            Console.WriteLine(" \n查詢類方法:\n");
            
            Console.WriteLine(" 1.獲取與指定節點標簽名稱匹配的所有節點的列表");
            XmlNodeList getElementsByTagName = xml.GetElementsByTagName("jobs");
            foreach (XmlNode i in getElementsByTagName)
            {
                Console.Write("\n getElementsByTagName(jobs): {0}\n", i.LocalName);
            }
            Console.WriteLine("\n ------------------------------\n");

            Console.WriteLine(" 特殊值“*”匹配所有標簽名稱");
            XmlNodeList getElementsByTagName2 = xml.GetElementsByTagName("*");
            foreach (XmlNode i in getElementsByTagName2)
            {
                Console.Write("\n getElementsByTagName(*): {0}\n", i.LocalName);
            }
            Console.WriteLine("\n ------------------------------\n");

 

運行結果:

 

 

     Console.WriteLine(" 2.獲取第一個按標簽匹配到的節點集合");
            //節點標簽需要從根節點開始一層一層到當前節點標簽
            XmlNodeList selectNodes = xml.SelectNodes("/note/jobs");
            foreach (XmlNode item in selectNodes)
            {
                C("SelectNodes", item.LocalName);
            }

            Console.WriteLine(" 3.選擇第一個按標簽匹配到的節點");
            //1.節點標簽需要從根節點開始一層一層到當前節點標簽
            XmlNode selectSingleNode = xml.SelectSingleNode("/note/jobs");
            C("SelectSingleNode", selectSingleNode.LocalName);

            Console.WriteLine(" 4.獲取具有指定 ID 的 XmlElement 節點");
            //1.這里的指定 ID,需要再 DTD 中定義屬於 ID 類型的屬性
            //2.比較麻煩,一般用不上,這里不做演示
            XmlElement getElementById = xml.GetElementById("");

 

運行結果:

 

 

   //新增和添加類方法

            //創建一個新節點
            XmlElement createElement = xml.CreateElement("1.createElement");

            //為指定節點新建屬性並賦值
            createElement.SetAttribute("2.setAttribute", "100");

            //不推薦以下為節點添加屬性的辦法,性能內存不佳,而且麻煩
            //1.創建指定名稱的屬性
            XmlAttribute createAttribute = xml.CreateAttribute("3.createAttribute");
            //2.設置屬性值
            createAttribute.Value = "200";
            //3.為指定節點添加指定的屬性
            createElement.SetAttributeNode(createAttribute);

            //為指定節點添加子節點
            //如果存在相同節點,不會覆蓋原節點
            rootElement.AppendChild(createElement);

            //創建一個節點
            //1.需要申明 XmlNodeType 和 Name,URI 可以不用申明
            //2.XmlNodeType.Element 類型的節點,就等於是創建一個 XmlElement
            //3.XmlNodeType 是一個枚舉類,18種類型節點,所以這是創建節點和創建元素的最大區別
            XmlNode createNode = xml.CreateNode(XmlNodeType.Element, "4.CreateNode", "");
            rootElement.AppendChild(createNode);

            //在當前節點的指定子節點 *前* 插入新節點(XmlNode)
            //1.refChild必須為當前節點的子節點
            //2.newChild可以是xmlNode或者xmlElement
            XmlElement insertBefore = xml.CreateElement("5.InsertBefore");
            XmlNode refChild = xml.SelectSingleNode("/note/jobs");
            rootElement.InsertBefore(insertBefore, refChild);

            //在當前節點的指定子節點 *后* 插入新節點(XmlNode)
            //1.refChild必須為當前節點的子節點
            //2.newChild可以是xmlNode或者xmlElement
            XmlElement insertAfter = xml.CreateElement("6.InsertAfter");
            rootElement.InsertAfter(insertAfter, refChild);

            //將節點從另一個文檔導入到當前文檔
            //1.importNode節點需要添加進當前的XML節點中,否則不會被添加進去
            //2.不同文檔之間無法直接添加對方節點,會報錯,需要通過導入節點來添加
            xml2 = new XmlDocument();
            xml2.Load(filePath2);
            XmlNode xml2node = xml2.SelectSingleNode("/xml2/ImportNode");
            //rootElement.AppendChild(xml2node); //此處會報錯,提示不同文檔
            XmlNode importNode = xml.ImportNode(xml2node, true);
            rootElement.AppendChild(importNode);

 

運行結果:

 

 

   //刪改類方法

            //將指定的節點添加到該節點的子節點列表的開頭(XmlNode)
            //1.newChild可以是xmlNode或者xmlElement
            refChild.PrependChild(createNode);

            //用新子節點替換舊子節點(XmlNode)
            //1.必須是當前節點的子節點
            XmlElement replaceChild = xml.CreateElement("ReplaceChild");
            rootElement.ReplaceChild(replaceChild, createElement);

            //移除當前節點的子節點(XmlNode)
            //1.被移除的節點必須為當前節點的直接子級,不能是子級的子級
            XmlNode removeChild = xml.SelectSingleNode("/note/jobs");
            rootElement.RemoveChild(removeChild);

            //移除當前節點的所有子節點和屬性(XmlNode)
            removeChild.RemoveAll();

            //保存XML文件,如果存在指定文件,則此方法會覆蓋它
            xml.Save(filePath);
        }

 

運行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM