Load file XML bằng C# và LINQ


Hôm nay, chúng ta sẽ cùng nhau tìm hiểu về cách nạp một tập tin XML vào trong ứng dụng viết bằng C# với sự hỗ trợ của LINQ. Qua đó, các bạn có thể tự tin viết các ứng dụng tương tác với tập tin XML theo mục đích của riêng mình.

Trước hết, các bạn cần phải hiểu sơ lược XML là gì? (Các bạn có thể xem bài giới thiệu tại đây). Nói đơn giản, XML là một tài liệu dạng văn bản mà sử dụng các thẻ được đặt tên để đánh dấu dữ liệu. Ví dụ sau mô tả một tài liệu XML lưu trữ thông tin về các quyển sách

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book id="B01">
        <title>Programming with C#</title>
        <author>Jackson</author>
        <price>150</price>
    </book>
    <book id="B02">
        <title>How to change my life</title>
        <author>Michael John</author>
        <price>200</price>
    </book>
</books>

Dòng đầu tiên của một tài liệu XML (không bắt buộc) là dòng chỉ dẫn xử lý (Processing Instruction). Và hầu như mọi tài liệu XML đều có dòng đầu tiên với nội dung giống hệt như vậy, hoặc là với một số thay đổi nhỏ.

Ngay sau chỉ dẫn xử lý sẽ đến nội dung chính của tài liệu XML. Một điều cần lưu ý là một tài liệu XML bất kỳ luôn phải có một thẻ gốc, trong trường hợp này là thẻ <books>. Bạn có thể tưởng tượng một tài liệu XML như là một cái cây và cây này luôn phải có một gốc. Trong cặp thẻ gốc này, chúng ta có thể đặt nhiều thẻ con khác nhau để chứa dữ liệu. Tài liệu XML ở trên có dạng thức giống mô hình cây sau:

image

Bây giờ chúng ta sẽ bắt tay vào công việc chính của bài hôm nay: viết code C# để nạp các thông tin từ tập tin XML trên vào trong chương trình.

Trong Visual Studio, chọn File –> New Project. Trong hộp thoại xuất hiện, chọn ngôn ngữ lập trình là C# và loại ứng dụng là Console Application. Đặt tên cho Project này là LoadXMLProgram

image

Sau đó, chúng ta sẽ thêm vào Project của chúng ta một tập tin XML để sử dụng làm ví dụ cho chương trình. Click chuột phải lên tên của Project trong Solution Explorer, chọn Add –> New Item. Trong cửa sổ hiện ra, chọn XML File, đặt tên của file này là books.xml, nội dung của tập tin này giống như đoạn XML ví dụ ở trên chúng ta vừa xét

image

Một điều cần lưu ý là bởi vì khi chúng ta biên dịch chương trình thì tập tin exe của chúng ta sẽ nằm trong thư mục Debug của project, trong khi tập tin XML mặc định không được copy theo, do đó sẽ dẫn đến lỗi nếu như chúng ta thực hiện biên dịch chương trình. Để khắc phục lỗi này, chúng ta hãy nhấp chuột chọn file books.xml trong Solution Explorer, trong ô Properties, thay đổi giá trị “Copy to Output Directory” thành “Copy if newer” hoặc “Copy Always

image

Để có thể làm việc với file XML dùng LINQ, chúng ta sẽ phải sử dụng các lớp và phương thức có trong namespace System.Xml.Linq. Double click vào tập tin Program.cs trong Solution Explorer và thêm đoạn mã sau vào phần đầu của tập tin nguồn.

using System.Xml.Linq;

Trong hàm Main, chúng ta khai báo một đối tượng của lớp XElement. Đối tượng này sẽ được khởi tạo như sau:

XElement xmlBook = XElement.Open(“books.xml”);

Phương thức tĩnh XElement.Open cho phép chúng ta nạp tập tin XML vào trong bộ nhớ. Trong dòng lệnh trên, chúng ta sử dụng tập tin books.xml nằm cùng thư mục với tập tin thực thi (đến đây thì bạn có thể hiểu rằng tại sao chúng ta phải chỉnh thuộc tính để tập tin books.xml được copy đồng thời với tập tin chương trình khi biên dịch). Đồng thời, đối tượng xmlBook sẽ lưu thông tin về thẻ gốc của tập tin XML này. Lưu ý rằng nếu như file XML của chúng ta không có thẻ gốc, chương trình sẽ phát sinh lỗi như sau:

image

Sau khi đã có được tham chiếu đến thẻ gốc, chúng ta sẽ thực hiện duyệt qua các phần tử Book trong nội dung file XML vừa được nạp vào. Để có thể lưu trữ được các thông tin này, chúng ta sẽ tạo thêm một lớp Book có các dữ liệu sau đây:

class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public float Price { get; set; }
}

Và tiếp đó là phần thú vị nhất trong chương trình. Đoạn mã sau đây sẽ cho phép chúng ta thực hiện duyệt qua các thông tin có trong tập tin books.xml và đưa vào trong một danh sách các Book.

List<Book> books = (from q in xmlBook.Elements("book")
                               select new Book
                               {
                                   Title = q.Element("title").Value,
                                   Author = q.Element("author").Value,
                                   Price = float.Parse(q.Element("price").Value)
                               }).ToList();

Trong đoạn mã trên, chúng ta trước hết tạo ra một List<Book> dùng để chứa thông tin về các Book. Sau đó, chúng ta sử dụng LINQ để duyệt qua các phần tử và đưa nó vào trong danh sách này.

Ghi chú: LINQ (Language-Integrated Query) là một kỹ thuật truy vấn được tích hợp vào trong các ngôn ngữ lập trình .NET nhằm giúp việc viết code và thao tác trên các dữ liệu trở nên dễ dàng hơn. Cú pháp của LINQ gần giống như cú pháp của SQL).

Các bước thực hiện của đoạn mã trên là như sau:

Bước 1: Gọi xmlBook.Elements(“book”), kết quả trả về của lời gọi này là danh sách các thẻ có tên “book” nằm trong thẻ gốc xmlBook và kèm theo các thông tin trong thẻ đó. Dựa vào nội dung của file books.xml mà chúng ta có thể đoán được rằng các thẻ trả về sẽ có những thẻ con là “title”, “author” và “price”.

Bước 2: Duyệt qua từng phần tử trong danh sách thẻ được trả về ở trên (nhờ cấu trúc from q in..), q ở đây là một biến tạm thời dùng để chỉ định phần tử hiện tại trong danh sách (q không cần phải khai báo hay chỉ định kiểu dữ liệu, trình biên dịch đủ thông minh để suy ra được kiểu dữ liệu của q từ kiểu dữ liệu của tập hợp trả về là gì).

Bước 3: Với mỗi phần tử trong danh sách đó, chúng ta thực hiện tạo ra một đối tượng Book với các thông tin tương ứng của phần tử đang xét. Như trong đoạn mã trên, với mỗi thẻ dữ liệu XML được trả về, chúng ta sẽ tạo đối tượng Book với Title, Author và Price là thông tin được chứa trong các thẻ con tương ứng. Lời gọi: q.Element(“title”).Value cho phép chúng ta lấy giá trị được chứa trong thẻ có tên “title” nằm trong q, tương tự đối với “Author” và “Price”. Lưu ý: chúng ta đã khai báo kiểu dữ liệu của Price trong lớp Book là float, do đó bắt buộc chúng ta phải chuyển đổi kiểu dữ liệu string lấy được từ thẻ “Price” về dạng float.

Bước 4: Sau khi đã tạo được một tập hợp các đối tượng Book, chúng ta chuyển đổi tập hợp này sang dạng List để phù hợp với kiểu dữ liệu của  biến books.

Nếu dữ liệu đã được nạp thành công, chúng ta có thể in ra màn hình dữ liệu đó bằng đoạn lệnh sau:

foreach (Book b in books)
{
    Console.WriteLine(b.Title + "-" + b.Author + "-" + b.Price);
}

Và chúng ta nhận được kết quả:

image

Như vậy là chúng ta đã hoàn thành việc nạp dữ liệu từ file XML vào trong một ứng dụng viết bằng C# chỉ với vài dòng code với sự trợ giúp của LINQ. LINQ còn được ứng dụng để sử dụng trong các loại dữ liệu khác, ví dụ như LINQ to SQL, LINQ to Object. Nếu biết sử dụng tính năng mới này thì chúng ta có thể giảm đáng kể thời gian rút trích dữ liệu và tập trung vào phần xử lý.

Các bạn có thể download mã nguồn của chương trình này về tại đây.

Tác giả: xuanchien

Tran Xuan Chien. Japan Advanced Institute of Science and Technology - Japan. Senior Developer - NUS Technology.

38 thoughts on “Load file XML bằng C# và LINQ”

  1. Bạn ơi, cho mình hỏi câu lệnh: public string Title { get; set; } là khai báo class Book có thuộc tính title à? thế còn get; set; là khai báo hàm à? bạn giải thích giup mình với. Hồi giờ mình tưởng khai báo hàm là set(); get(); mà. Thanks bạn nhiu!

  2. Bạn ơi, mình run được tới màn hình đen rui, nhưng chỉ xem được trong chốc lát thôi à, bạn chỉ mình lệnh để mình dừng màn hình đen tới khi nào tắt đi mới thôi. Thanks bạn!

  3. Bạn ơi! Mình chỉ mới tìm hiểu về XML thui, mục đích là muốn đối sánh 2 file xml để tìm ra sự sai khác giữa chúng. Nhưng mình gặp khó khăn là: không truy vấn được file xml kết quả để in ra màn hình. Bạn giúp mình truy vấn file xml này với. Thanks bạn nhiu lắm!

    TEST DELETED
    2/6/1998

    ZEYNEP – Inserted
    1/1/2009

    1. Bạn có thể ghi rõ hơn nội dung của file XML được không? Nếu cấu trúc của 2 tập tin XML là khác nhau thì bạn nạp tập tin đầu tiên rồi sau đó nạp tập tin thứ 2 và thực hiện kiểm tra theo thứ tự từng dữ liệu có được

  4. Bạn ơi,mình đâu tìm thấy chỗ nào để upload file đâu, để mà send file xml qua được. Cái là mình ko biết viết câu lệnh để truy vấn đối tượng 1 sau đó truy vấn tiếp đối tượng 2, 3 bên trong nó đó. Bạn giúp mình với. Đây là address yahoo của mình: huonguit@yahoo.com. Thank bạn nhiu!

  5. bạn ơi, file xml cua mình có dạng, bạn chỉ giúp mình câu truy vấn để mình in được tới name: là tran van A và nguyen van B với bạn. Thanks bạn!

    tran van A

    nguyen van B

  6. Cảm ơn anh! Bài viết rất hay!
    cho em hỏi nếu mình làm trên window Form thì thế nào ạ? em làm thử y như vậy nhưng chỗ

    foreach (Book b in books)
    {
    Console.WriteLine(b.Title + "-" + b.Author + "-" + b.Price);
    }

    thì em thay là:

    foreach(Book b in books)
    {
    richTextBox1.Text=b.Title+ "-" + b.Author + "-" + b.Price;
    }

    nhưng không được!

    1. Em gán nội dung cho thuộc tính Text của một RichTextBox thì yêu cầu giá trị gán phải ở dạng chuỗi (string). Trong khi đó nội dung em gán có b.Price là kiểu số nên nó sẽ báo lỗi. Để gán được thì em có thể sử dụng phương thức ToString() như sau:
      richTextBox1.Text = b.Title + “-” + b.Author + “-” + b.Price.ToString();
      Thân,

      1. À. em không để ý chỗ đó😀
        nó báo lỗi khác anh à:
        Lỗi là:
        Error 1 A field initializer cannot reference the non-static field, method, or property ‘XML_Linq_WindowForm.Form1.xmlBook’ C:\Users\vankhai\Documents\Visual Studio 2008\Projects\XML_Linq_WindowForm\XML_Linq_WindowForm\Form1.cs 20

        ở chỗ:
        List books = (from q in xmlBook.Elements("book")
        select new Book
        {
        Title = q.Element("title").Value,
        Author = q.Element("author").Value,
        Price = float.Parse(q.Element("price").Value)
        }).ToList();

  7. EM sửa nó thành:
    static XElement xmlBook = XElement.Load(“books.xml”);

    thì hết lỗi và chạy đc. nhưng chỉ có 1 quyển sách đc in ra thôi: How to change my life-Michael John-200

    không biết tại sao nữa !

  8. Em làm đc rồi. nhưng vẫn không hiểu chỗ: static XElement xmlBook = XElement.Load(“books.xml”);
    Tại sao trong Window Form nó phải là static mà trong môi trường Console nó không cần static??

    1. Anh không nghĩ là có sự khác biệt giữa Console và Windows Forms vì các đoạn code này không hề liên quan đến giao diện người dùng. Em thử kiểm tra lại phiên bản của từng ứng dụng để chắc chắn là các ứng dụng này đều giống nhau.

  9. Bạn ơi cho mình hỏi vấn đề ngoài lề tí. Làm thế nào để thêm chức năng SyntaxHighlighter code như trang của bạn vậy.? .mình tìm trên mạng toàn thấy plugin cho wordpress.org không à, không thấy cách thêm cho wordpress.com. Bạn có thể chỉ mình cách làm ko..?

  10. mình đọc rùi mà không thấy ví dụ nên cũng ko hiểu lắm.mình đã thử bỏ đoạn code vào thẻ rùi mà không biết cú pháp sao để chọn ngôn ngữ với bật tính năng gutter (true/false) đánh số dòng.

  11. Bạn ơi, mình có một thắc mắc về linq, bạn chỉ giúp mình nha. Mình đổ cột KhachHang vào combobox cbmaloaiphong thì ở datagirdview dtphongkhachsan lại sinh thêm một cột KhachHang ghi là qlks.KhachHang. Vậy mình phải làm sao bỏ cột KhachHang trên datagirdview được.

    code:
    var query = from n in data.LoaiPhongs
    select n;
    cbmaloaiphong.DataSource=query;
    ………………………
    Ở trên là đoạn code mà mình dùng để đổ dữ liệu vào combobox. Cảm ơn bạn nhiều! ^^

  12. Em đã làm theo cách dùng LINQ của anh để đọc nội dung file XML cho ra một List các đối tượng thành công nhưng khi chạy ứng dụng em cần thay đổi nội dung các node trong List rồi lưu lại List đó xuống file XML cũ thì phải làm như thế nào ạ. Anh có thể demo với chính ví dụ này của anh được không ạ. Em cảm ơn rất nhiều !

  13. HI anh chiến
    cho em hỏi 1 chút về cái LINQ.

    Khi em load form có code:

    Phanquyenenties context = new Phanquanenties();
    var query = from cacform in form
    join nhomform in groupform on cacform.id_form equal nhomform.id_form
    select new { nhomform.name_groupform, cacform.name, cacform.xoa, cacform.sua};
    gridcontrol1.Datasouce = query.tolist();

    Khi load lên em không thể edit được trên gridcontrol.
    Nếu em không select new mà chỉ select 1 cái thì có thể sửa được nhưng select new em không thể edit được.

    Vậy em phải làm thế nào để edit được khi select new 2 hoặc nhiều table database ?
    Và em phải làm thế nào để có thể sửa trực tiếp dữ liệu trên gridcontrol hay datagridview mà không phải thông qua textbox.. mà chỉ cần click vào row trong gridcontrol rồi sửa rồi lưu lại luôn ?

    Mong anh hướng dẫn và giúp đỡ.
    Thank

    1. Để cho phép edit trực tiếp trên Grid thì bạn phải xử lý sự kiện RowUpdating của gridView. Trong sự kiện này bạn sẽ lấy dữ liệu trong dòng đang edit và lưu xuống database.

  14. anh phân tích giúp e 2 dòng code sau khác nhau ntn dc ko ạ. dòng số 2 sao lại ép kiểu, ép kiểu để làm j vậy ạ!
    from rss in xmlBook.Elements(“book”)
    from rss in XElement.Parse(e.Result).Descendants(“book”)

    1. Ở dòng đầu tiên thì xmlBook đã là 1 object theo kiểu XML rồi. Còn ở dòng thứ 2 thì e.Result có thể là kiểu String, vì thế phải chuyển nó về dạng XML object mới có thể thao tác được.

      Thân

      1. e hỏi thêm 1 chút, a giúp e tí nha !
        e đã xử lý dc file xml, đã load dc nội dung của trang web, bài báo ( cụ thể e làm trên vnxpress ) nhưng load lên cả quảng cáo luôn
        a có cachs nào mà chỉ load lên chỉ nội dung bài báo dc ko?

  15. Chào bạn ! Cảm ơn bài viết của bạn !
    Bạn cho mình hỏi, mình có file SinhVien.mxl (lưu thông tin của các sinh viên). GIờ mình muốn hiển thị thông tin của sinh viên theo yêu cầu (ví dụ: những sinh viên quê ở hà nội) thì làm như thế nào ?

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s