Cách xử lý XML trong C #


85

Cách tốt nhất để xử lý các tài liệu XML, XSD, v.v. trong C # 2.0 là gì?

Sử dụng các lớp nào, v.v. Các phương pháp hay nhất để phân tích cú pháp và tạo tài liệu XML là gì, v.v.

CHỈNH SỬA: Đề xuất .Net 3.5 cũng được hoan nghênh.


Đối với những người cũng đang cố gắng tìm một giải pháp khả thi hơn, hãy bỏ qua điều này. Nó là một thư viện .NET cũ. Sử dụng XDocument thay vào đó, và bạn sẽ tiết kiệm được việc khoét mắt vì thất vọng
AER

Câu trả lời:


177

Phương tiện chính để đọc và viết trong C # 2.0 được thực hiện thông qua lớp XmlDocument . Bạn có thể tải trực tiếp hầu hết các cài đặt của mình vào XmlDocument thông qua XmlReader mà nó chấp nhận.

Đang tải XML trực tiếp

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

Tải XML từ tệp

XmlDocument document = new XmlDocument();
document.Load(@"C:\Path\To\xmldoc.xml");
// Or using an XmlReader/XmlTextReader
XmlReader reader = XmlReader.Create(@"C:\Path\To\xmldoc.xml");
document.Load(reader);

Tôi thấy cách dễ nhất / nhanh nhất để đọc một tài liệu XML là sử dụng XPath.

Đọc tài liệu XML bằng XPath (Sử dụng XmlDocument cho phép chúng tôi chỉnh sửa)

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

// Select a single node
XmlNode node = document.SelectSingleNode("/People/Person[@Name = 'Nick']");

// Select a list of nodes
XmlNodeList nodes = document.SelectNodes("/People/Person");

Nếu bạn cần làm việc với các tài liệu XSD để xác thực tài liệu XML, bạn có thể sử dụng nó.

Xác thực Tài liệu XML dựa trên các Lược đồ XSD

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd

XmlReader reader = XmlReader.Create(pathToXml, settings);
XmlDocument document = new XmlDocument();

try {
    document.Load(reader);
} catch (XmlSchemaValidationException ex) { Trace.WriteLine(ex.Message); }

Xác thực XML chống lại XSD tại mỗi nút (CẬP NHẬT 1)

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd
settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);

XmlReader reader = XmlReader.Create(pathToXml, settings);
while (reader.Read()) { }

private void settings_ValidationEventHandler(object sender, ValidationEventArgs args)
{
    // e.Message, e.Severity (warning, error), e.Error
    // or you can access the reader if you have access to it
    // reader.LineNumber, reader.LinePosition.. etc
}

Viết tài liệu XML (thủ công)

XmlWriter writer = XmlWriter.Create(pathToOutput);
writer.WriteStartDocument();
writer.WriteStartElement("People");

writer.WriteStartElement("Person");
writer.WriteAttributeString("Name", "Nick");
writer.WriteEndElement();

writer.WriteStartElement("Person");
writer.WriteStartAttribute("Name");
writer.WriteValue("Nick");
writer.WriteEndAttribute();
writer.WriteEndElement();

writer.WriteEndElement();
writer.WriteEndDocument();

writer.Flush();

(CẬP NHẬT 1)

Trong .NET 3.5, bạn sử dụng XDocument để thực hiện các tác vụ tương tự. Tuy nhiên, sự khác biệt là bạn có lợi thế khi thực hiện Truy vấn Linq để chọn chính xác dữ liệu bạn cần. Với việc bổ sung các trình khởi tạo đối tượng, bạn có thể tạo một truy vấn thậm chí trả về các đối tượng theo định nghĩa của riêng bạn ngay trong chính truy vấn.

    XDocument doc = XDocument.Load(pathToXml);
    List<Person> people = (from xnode in doc.Element("People").Elements("Person")
                       select new Person
                       {
                           Name = xnode.Attribute("Name").Value
                       }).ToList();

(CẬP NHẬT 2)

Dưới đây là một cách hay trong .NET 3.5 là sử dụng XDocument để tạo XML. Điều này làm cho mã xuất hiện trong một mẫu tương tự với đầu ra mong muốn.

XDocument doc =
        new XDocument(
              new XDeclaration("1.0", Encoding.UTF8.HeaderName, String.Empty),
              new XComment("Xml Document"),
              new XElement("catalog",
                    new XElement("book", new XAttribute("id", "bk001"),
                          new XElement("title", "Book Title")
                    )
              )
        );

tạo ra

<!--Xml Document-->
<catalog>
  <book id="bk001">
    <title>Book Title</title>
  </book>
</catalog>

Vẫn thất bại, bạn có thể xem bài viết MSDN này có nhiều ví dụ mà tôi đã thảo luận ở đây và hơn thế nữa. http://msdn.microsoft.com/en-us/library/aa468556.aspx


3
Bạn có thể muốn chỉ ra rằng bạn đang sử dụng XDocument trong ví dụ cuối cùng vì XDocument khá khác với XmlDocument
Aaron Powell

2
Điều chỉnh; không có C # 3.5; ý bạn là .NET 3.5 và C # 3.0
Marc Gravell

ồ, và "on the fly" [đối tượng khởi tạo] sẽ hoạt động phần lớn giống với C # 3.0 và XmlDocument - mặc dù vậy vẫn là một câu trả lời hay (+1)
Marc Gravell

Có thể đáng nói rằng nếu bạn đang tải một tài liệu để truy vấn bằng XPath (và không phải để chỉnh sửa) thì việc sử dụng XPathDocument sẽ hiệu quả hơn rất nhiều
Oliver Hallam

Việc xác thực lược đồ này có được thực hiện từng nút không? Nếu không, có cách nào để làm điều đó từng nút không?
Malik Daud Ahmad Khokhar 21/10/08

30

Nó phụ thuộc vào kích thước; đối với xml kích thước nhỏ đến trung bình, một DOM như XmlDocument (bất kỳ phiên bản C # /. NET nào) hoặc XDocument (.NET 3.5 / C # 3.0) là người chiến thắng rõ ràng. Để sử dụng xsd, Bạn có thể tải xml bằng XmlReader và XmlReader chấp nhận (để Tạo ) XmlReaderSettings . Các đối tượng XmlReaderSettings có thuộc tính Schemas có thể được sử dụng để thực hiện xác thực xsd (hoặc dtd).

Đối với việc viết xml, những điều tương tự cũng áp dụng, lưu ý rằng việc bố trí nội dung với LINQ-to-XML (XDocument) dễ dàng hơn một chút so với XmlDocument cũ hơn.

Tuy nhiên, đối với xml lớn, DOM có thể chiếm quá nhiều bộ nhớ, trong trường hợp đó bạn có thể cần sử dụng trực tiếp XmlReader / XmlWriter.

Cuối cùng, để thao tác với xml, bạn có thể muốn sử dụng XslCompiledTransform (một lớp xslt).

Giải pháp thay thế để làm việc với xml là làm việc với một mô hình đối tượng; bạn có thể sử dụng xsd.exe để tạo các lớp đại diện cho một mô hình tuân thủ xsd và chỉ cần tải xml dưới dạng các đối tượng , thao tác với nó với OO, sau đó tuần tự hóa lại các đối tượng đó; bạn làm điều này với XmlSerializer .


Để thao tác (thêm / phần tử suppr) một tài liệu XML lớn (40k dòng). Cách tốt nhất là gì? Tôi đã từng sử dụng LINQ-to-XML.
Neyoh

12

câu trả lời của nyxtom rất hay. Tôi muốn thêm một số thứ vào nó:

Nếu bạn cần quyền truy cập chỉ đọc vào một tài liệu XML, đó XPathDocumentlà một đối tượng có trọng lượng nhẹ hơn nhiều XmlDocument.

Nhược điểm của việc sử dụng XPathDocumentlà bạn không thể sử dụng các phương pháp quen thuộc SelectNodesSelectSingleNodecủa XmlNode. Thay vào đó, bạn phải sử dụng các công cụ mà nó IXPathNavigablecung cấp: sử dụng CreateNavigatorđể tạo XPathNavigatorvà sử dụng XPathNavigatorđể tạo XPathNodeIterators để lặp lại danh sách các nút bạn tìm thấy qua XPath. Điều này thường yêu cầu một vài dòng mã hơn các XmlDocumentphương thức.

Nhưng: các lớp XmlDocumentXmlNodethực thi IXPathNavigable, vì vậy bất kỳ mã nào bạn viết để sử dụng các phương thức đó trên an XPathDocumentcũng sẽ hoạt động trên an XmlDocument. Nếu bạn đã quen với việc viết ngược IXPathNavigable, các phương thức của bạn có thể hoạt động với một trong hai đối tượng. (Đây là lý do tại sao sử dụng XmlNodeXmlDocumenttrong các chữ ký phương thức được FxCop gắn cờ.)

Đáng tiếc, XDocumentXElement(và XNodeXObject) không thực hiện IXPathNavigable.

Một điều khác không có trong câu trả lời của nyxtom là XmlReader. Bạn thường sử dụng XmlReaderđể tránh chi phí phân tích luồng XML thành một mô hình đối tượng trước khi bạn bắt đầu xử lý nó. Thay vào đó, bạn sử dụng một XmlReaderđể xử lý luồng đầu vào một nút XML tại một thời điểm. Đây thực chất là câu trả lời của .NET cho SAX. Nó cho phép bạn viết mã rất nhanh để xử lý các tài liệu XML rất lớn.

XmlReader cũng cung cấp cách đơn giản nhất để xử lý các phân đoạn tài liệu XML, ví dụ: luồng các phần tử XML không có phần tử bao gồm mà tùy chọn FOR XML RAW của SQL Server trả về.

Mã bạn viết bằng cách sử dụng XmlReaderthường được kết hợp rất chặt chẽ với định dạng của XML mà nó đang đọc. Sử dụng XPath cho phép mã của bạn được kết hợp lỏng lẻo hơn nhiều với XML, đó là lý do tại sao nó thường là câu trả lời đúng. Nhưng khi bạn cần sử dụng XmlReader, bạn thực sự cần nó.


3
Lưu ý rằng có một phương thức mở rộng XPathNavigator CreateNavigator(this XNode node)để tạo một XPathNavigatortừ an XNode(bao gồm lớp dẫn xuất XDocument).
Dave

5

Trước hết, hãy làm quen với các lớp XDocumentXElement mới , vì chúng là một cải tiến so với họ XmlDocument trước đó.

  1. Họ làm việc với LINQ
  2. Chúng nhanh hơn và nhẹ hơn

Tuy nhiên , bạn có thể vẫn phải sử dụng các lớp cũ để làm việc với mã kế thừa - đặc biệt là các proxy đã tạo trước đó. Trong trường hợp đó, bạn sẽ cần phải làm quen với một số mẫu để tương tác giữa các lớp xử lý XML này.

Tôi nghĩ câu hỏi của bạn khá rộng và sẽ đòi hỏi quá nhiều trong một câu trả lời duy nhất để cung cấp thông tin chi tiết, nhưng đây là câu trả lời chung đầu tiên tôi nghĩ đến và coi như là một khởi đầu.


Tôi đồng ý rằng chúng (XDocument, v.v.) rất tuyệt, nhưng OP đã hỏi về C # 2.0.
Marc Gravell


2

Nếu bạn đang làm việc trong .NET 3.5 và bạn không có mã thử nghiệm, bạn có thể kiểm tra LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to- xsd-alpha-0-2.aspx ) sẽ tạo ra các lớp .NET từ XSD (bao gồm cả các quy tắc tích hợp sẵn từ XSD).

Sau đó, nó có khả năng ghi thẳng ra tệp và đọc từ tệp đảm bảo rằng nó tuân thủ các quy tắc XSD.

Tôi chắc chắn khuyên bạn nên có một XSD cho bất kỳ tài liệu XML nào mà bạn làm việc:

  • Cho phép bạn thực thi các quy tắc trong XML
  • Cho phép người khác xem XML được / sẽ được cấu trúc như thế nào
  • Có thể được sử dụng để xác thực XML

Tôi thấy rằng Liquid XML Studio là một công cụ tuyệt vời để tạo XSD và hoàn toàn miễn phí!


2

Viết XML với lớp XmlDocument

//itemValues is collection of items in Key value pair format
//fileName i name of XML file which to creatd or modified with content
    private void WriteInXMLFile(System.Collections.Generic.Dictionary<string, object> itemValues, string fileName)
    {
        string filePath = "C:\\\\tempXML\\" + fileName + ".xml";
        try
        {

            if (System.IO.File.Exists(filePath))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(filePath);                   

                XmlNode rootNode = doc.SelectSingleNode("Documents");

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);


                foreach (string key in itemValues.Keys)
                {

                    XmlNode attrNode = doc.CreateElement(key);
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);
                doc.Save(filePath);
            }
            else
            {
                XmlDocument doc = new XmlDocument();
                using(System.IO.FileStream fs = System.IO.File.Create(filePath))
                {
                    //Do nothing
                }

                XmlNode rootNode = doc.CreateElement("Documents");
                doc.AppendChild(rootNode);
                doc.Save(filePath);

                doc.Load(filePath);

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);

                foreach (string key in itemValues.Keys)
                {                          
                    XmlNode attrNode = doc.CreateElement(key);                           
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);

                doc.Save(filePath);

            }
        }
        catch (Exception ex)
        {

        }

    }

OutPut look like below
<Dcouments>
    <Document>
        <DocID>01<DocID>
        <PageName>121<PageName>
        <Author>Mr. ABC<Author>
    <Dcoument>
    <Document>
        <DocID>02<DocID>
        <PageName>122<PageName>
        <Author>Mr. PQR<Author>
    <Dcoument>
</Dcouments>

1

Nếu bạn tạo tập dữ liệu đã nhập trong trình thiết kế thì bạn sẽ tự động nhận được xsd, một đối tượng được nhập mạnh và có thể tải và lưu xml bằng một dòng mã.


Tôi đã thành công lớn với DataSet's. Họ cũng rất thân thiện với Cơ sở dữ liệu.
User1

1

Ý kiến ​​cá nhân của tôi, với tư cách là một lập trình viên C #, là cách tốt nhất để xử lý XML trong C # là ủy quyền phần mã đó cho một dự án VB .NET. Trong .NET 3.5, VB .NET có XML Literals, giúp xử lý XML trực quan hơn nhiều. Xem ví dụ ở đây:

Tổng quan về LINQ sang XML trong Visual Basic

(Đảm bảo đặt trang để hiển thị mã VB, không phải mã C #.)

Tôi muốn viết phần còn lại của dự án bằng C #, nhưng xử lý XML trong một dự án VB được tham chiếu.


Nó không đáng để chuyển sang vb chỉ cho nghĩa đen XML. XML chỉ giải quyết các chữ. Nếu xml được chuyển vào dưới dạng tham số, hỗ trợ theo nghĩa đen của XML không mang lại cho bạn nhiều lợi ích. Thay vào đó, cú pháp kế thừa của vb.net sẽ làm hỏng trải nghiệm lập trình thú vị của C #.
Gqqnbig

0

nyxtom,

"Doc" và "xdoc" không nên khớp trong Ví dụ 1?

XDocument **doc** = XDocument.Load(pathToXml);
List<Person> people = (from xnode in **xdoc**.Element("People").Elements("Person")
                   select new Person
                   {
                       Name = xnode.Attribute("Name").Value
                   }).ToList();

Tôi đã gửi một bản chỉnh sửa để được chấp thuận cho câu trả lời mà bạn đang đề cập đến, tuy nhiên đây thực sự nên là một nhận xét, không phải là một câu trả lời.
David Thompson

Cảm ơn David. Đồng ý, nó sẽ không cho phép tôi bình luận vào thời điểm đó. Không chắc chắn lý do tại sao.
mokumaxCraig

0

Câu trả lời của Cookey là tốt ... nhưng đây là hướng dẫn chi tiết về cách tạo một đối tượng được đánh máy mạnh từ XSD (hoặc XML) và tuần tự hóa / deserialize trong một vài dòng mã:

Hướng dẫn


"Trang bạn đang tìm kiếm không tồn tại." :(
Ian Grainger

0

Nếu bạn cần chuyển đổi dữ liệu giữa XmlNode<=> XNode<=> XElement
(ví dụ: để sử dụng LINQ), Phần mở rộng này có thể hữu ích cho bạn:

public static class MyExtensions
{
    public static XNode GetXNode(this XmlNode node)
    {
        return GetXElement(node);
    }

    public static XElement GetXElement(this XmlNode node)
    {
        XDocument xDoc = new XDocument();
        using (XmlWriter xmlWriter = xDoc.CreateWriter())
            node.WriteTo(xmlWriter);
        return xDoc.Root;
    }

    public static XmlNode GetXmlNode(this XElement element)
    {
        using (XmlReader xmlReader = element.CreateReader())
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);
            return xmlDoc;
        }
    }

    public static XmlNode GetXmlNode(this XNode node)
    {
        return GetXmlNode(node);
    }
}

Sử dụng:

XmlDocument MyXmlDocument = new XmlDocument();
MyXmlDocument.Load("MyXml.xml");
XElement MyXElement = MyXmlDocument.GetXElement(); // Convert XmlNode to XElement
List<XElement> List = MyXElement.Document
   .Descendants()
   .ToList(); // Now you can use LINQ
...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.