引言
雖然現在Json在我們的數據交換中越來越成熟,但XML格式的數據還有很重要的地位。
C#中對XML的處理也不斷優化,那么我們如何選擇XML的這幾款處理類 XmlReader,XDocument 和XmlDocument了?
本文就從對照的方式來總結C#中XML的用法。
簡介
System.Xml 命名空間(XmlDocument)為處理 XML 提供基於標准的支持。
LINQ to XML(XDocument )可以進行以下操作:
-
從文件或流加載 XML。
-
將 XML 序列化為文件或流。
-
使用功能構造從頭創建 XML 樹。
-
使用 LINQ 查詢來查詢 XML 樹。
-
操作內存中的 XML 樹。
-
使用 XSD 驗證 XML 樹。
-
組合使用這些功能將 XML 樹從一種形狀轉換為另一種形狀。
XmlReader,XDocument 和XmlDocument
XDocument 和XmlDocument會把所有的XML所有的節點加載到內存中,而XmlReader則不會把所有節點一起加載到內存,而在一定的內存下處理較大的XML。
如果XML文件結構固定,處理比較簡單,建議使用XmlReader可以提高程序的性能。
如果XML文件不大或者要做復雜的處理建議使用XDocument。Linq 讓程序員省去了很多繁瑣冗余的代碼,並且兼容設備也比較多,不像XmlDocument在一些設備和系統中不支持。
XDocument VS. XmlDocument
| 比較項 | XmlDocument(經典DOM API) | XDocument (LINQ to XML API) |
| 需要熟悉DOM知識 | ||
| 支持的.NetFramework版本 | .NET version 1.0 + | .NET version 3.5 or later(Linq引入后) |
| 雜項 | Unity3D projects for Windows 8. Xbox 360 and Windows Phone OS 7.0,必須使用XDocument |
|
| Namespace | System.Xml | System.Xml.Linq |
| LINQ to XML | 不支持 | 支持 |
| 行號信息 | 不能提供行號信息 | 通過IXmlLineInfo提供了行號信息 |
| 命名空間 | 支持寫 | 支持元素級寫 |
| XPath | 不支持 | 支持, 參考System.Xml.XPath |
| 注釋 | 不支持 | 支持可擴展的批注集,請參見 LINQ to XML 批注。 |
| 校驗Schema | 支持,參考Validate(ValidationEventHandler) | 支持 ,參考Validate(XmlSchemaSet, ValidationEventHandler) |
| 加載XML | 成員方法加載(需要先new XmlDocument()) | 靜態方法XElement.Load(@"books.xml") |
創建XML文檔
使用XmlDocument 的示例
XmlDocument doc = new XmlDocument();
XmlElement name = doc.CreateElement("Name");
name.InnerText = "Patrick Hines";
XmlElement phone1 = doc.CreateElement("Phone");
phone1.SetAttribute("Type", "Home");
phone1.InnerText = "206-555-0144";
XmlElement phone2 = doc.CreateElement("Phone");
phone2.SetAttribute("Type", "Work");
phone2.InnerText = "425-555-0145";
XmlElement street1 = doc.CreateElement("Street1");
street1.InnerText = "123 Main St";
XmlElement city = doc.CreateElement("City");
city.InnerText = "Mercer Island";
XmlElement state = doc.CreateElement("State");
state.InnerText = "WA";
XmlElement postal = doc.CreateElement("Postal");
postal.InnerText = "68042";
XmlElement address = doc.CreateElement("Address");
address.AppendChild(street1);
address.AppendChild(city);
address.AppendChild(state);
address.AppendChild(postal);
XmlElement contact = doc.CreateElement("Contact");
contact.AppendChild(name);
contact.AppendChild(phone1);
contact.AppendChild(phone2);
contact.AppendChild(address);
XmlElement contacts = doc.CreateElement("Contacts");
contacts.AppendChild(contact);
doc.AppendChild(contacts);
使用XDocument 的示例
XElement contacts =
new XElement("Contacts",
new XElement("Contact",
new XElement("Name", "Patrick Hines"),
new XElement("Phone", "206-555-0144",
new XAttribute("Type", "Home")),
new XElement("phone", "425-555-0145",
new XAttribute("Type", "Work")),
new XElement("Address",
new XElement("Street1", "123 Main St"),
new XElement("City", "Mercer Island"),
new XElement("State", "WA"),
new XElement("Postal", "68042")
)
)
);
加載XML文件
使用XmlDocument 的示例
XmlDocument booksFromFile = new XmlDocument(); booksFromFile.Load(@"books.xml");
使用XDocument 的示例
XElement booksFromFile = XElement.Load(@"books.xml");
命名空間的處理
使用XmlDocument 的示例
public void addXmlns()
{
string xml = @"<?xml version=""1.0""?>
<kml>
<Document>
<Placemark>
</Placemark>
</Document>
</kml>";
var xmldoc = new XmlDocument();
xmldoc.LoadXml(xml);
xmldoc.DocumentElement.SetAttribute("xmlns", "http://www.opengis.net/kml/2.2");
xmldoc.DocumentElement.SetAttribute("xmlns:gx", "http://www.google.com/kml/ext/2.2");
xmldoc.DocumentElement.SetAttribute("xmlns:kml", "http://www.opengis.net/kml/2.2");
xmldoc.DocumentElement.SetAttribute("xmlns:atom", "http://www.w3.org/2005/Atom");
xmldoc.DocumentElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
string message;
message = xmldoc.InnerXml;
Console.WriteLine(message); // shows the updated xml
}
使用XDocument 的示例
示例1,增加namespace
XNamespace ns = "http://somewhere.com"; XElement element = new XElement(ns + "elementName"); // etc
示例2,讀取含有namespace的文件
string markup = @"
<aw:Root xmlns:aw='http://www.adventure-works.com'>
<aw:Child1>child one data</aw:Child1>
<aw:Child2>child two data</aw:Child2>
</aw:Root>";
XmlReader reader = XmlReader.Create(new StringReader(markup));
XElement root = XElement.Load(reader);
XmlNameTable nameTable = reader.NameTable;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("aw", "http://www.adventure-works.com");
XElement child1 = root.XPathSelectElement("./aw:Child1", namespaceManager);
Console.WriteLine(child1);
XDocument
XDocument VS. XElement
| XDocument | XElement |
| XDocument.Load() 加載整個XML文檔 包括根節點 | XElement.Load()不會加載XML的根節點 |
XElement.Load()示例代碼
File.WriteAllText("Test.xml", @"<Root>
<Child1>1</Child1>
<Child2>2</Child2>
<Child3>3</Child3>
</Root>");
Console.WriteLine("Querying tree loaded with XElement.Load");
Console.WriteLine("----");
XElement doc = XElement.Load("Test.xml");
IEnumerable<XElement> childList =
from el in doc.Elements()
select el;
foreach (XElement e in childList)
Console.WriteLine(e);
XDocument.Load() 示例代碼:
File.WriteAllText("Test.xml", @"<Root>
<Child1>1</Child1>
<Child2>2</Child2>
<Child3>3</Child3>
</Root>");
Console.WriteLine("Querying tree loaded with XDocument.Load");
Console.WriteLine("----");
XDocument doc = XDocument.Load("Test.xml");
IEnumerable<XElement> childList =
from el in doc.Elements()
select el;
foreach (XElement e in childList)
Console.WriteLine(e);
XPath
XPath的強大之處在於處理元素導航還可以進行計算
- XPathSelectElement - Single Element
- XPathSelectElements - Node Set
- XPathEvaluate - Scalars and others
示例:
XML文檔
<xml>
<foo>
<baz id="1">10</baz>
<bar id="2" special="1">baa baa</bar>
<baz id="3">20</baz>
<bar id="4" />
<bar id="5" />
</foo>
<foo id="123">Text 1<moo />Text 2
</foo>
</xml>
C#處理計算
var node = xele.XPathSelectElement("/xml/foo[@id='123']");
var nodes = xele.XPathSelectElements(
"//moo/ancestor::xml/descendant::baz[@id='1']/following-sibling::bar[not(@special='1')]");
var sum = xele.XPathEvaluate("sum(//foo[not(moo)]/baz)");
這里只是總結知識點,但具體的關於更多XPath的內容可以移步到XPath 教程
XML 批注(注釋)
public class MyAnnotation
{
private string tag;
public string Tag { get { return tag; } set { tag = value; } }
public MyAnnotation(string tag)
{
this.tag = tag;
}
}
class Program
{
static void Main(string[] args)
{
XElement root = new XElement("Root", "content");
root.AddAnnotation(new MyAnnotation("T1"));
root.AddAnnotation(new MyAnnotation("T2"));
root.AddAnnotation("abc");
root.AddAnnotation("def");
IEnumerable<object> annotationList;
annotationList = root.Annotations(typeof(MyAnnotation));
foreach (object ma in annotationList)
Console.WriteLine(((MyAnnotation)ma).Tag);
Console.WriteLine("----");
IEnumerable<object> stringAnnotationList;
stringAnnotationList = root.Annotations(typeof(string));
foreach (object str in stringAnnotationList)
Console.WriteLine((string)str);
}
}
總結
現在再寫XML相關的程序建議直接使用XDocument,XmlDocument只是主要還是兼容以前的代碼。
另外XPath功能讓XDocument如虎添翼,所以大家可以多研究下XPath.
至於XSD和XSL本文不做涉及,又需要的朋友參看參考文獻
參考
2.使用XmlReader讀Xml,使用XmlWriter寫Xml
9.W3CSchool中提供的XML相關課程


