© 2020, Developed by Hieu Dev

Làm quen với XML trong lập trình C# .NET

Trong lập trình web, việc làm việc với JSON hoặc XML là điều khó tránh khỏi. Tuy bạn đã quá quen thuộc với việc với JSON, vì XML không phổ biến như JSON, nhưng trong vài trường hợp buộc bạn phải làm việc với XML, ví dụ khi bạn làm việc với 3rd party, và API document require payload và response phải là XML, vì thế bài viết này là một hành trang tốt nhất với bạn hiện tại.

Làm quen với XML trong lập trình C# .NET

XML là gì?

XML là từ viết tắt của từ eXtensible Markup Language, dùng để cấu trúc, lưu trữ và trao đổi dữ liệu giữa các ứng dụng và lưu trữ dữ liệu. 

Nếu bạn biết HTML, bạn sẽ dễ dàng hiểu được XML vì XML cũng là một ngôn ngữ đánh dấu. Nó là một định dạng dựa trên văn bản đơn giản để biểu diễn dữ liệu/thông tin có cấu trúc. XML được sử dụng trong tài liệu, dữ liệu, cấu hình, giao tiếp giữa các ứng dụng, v.v…

Khác với HTML bạn chỉ dùng được các thẻ đã được định nghĩa trước như p, h1, h2, table,...  thì XML bạn có thể quyết định được tên thẻ và cấu trúc tài liệu mà không có giới hạn và quy tắc.

Để tạo nên một XML thì chúng ta cần tuân theo quy tắc sau:
  • Tên tag phân biệt chữ hoa, chữ thường
  • Một XML document chỉ có một element gốc
  • Giá trị của thuộc tính phải đặt vào trong dấu nháy đơn
  • Mỗi XML element phải có tag đóng
  • Các tag phải được lồng nhau có trình tự.

Làm quen với XML trong C#

Bây giờ, mình sẽ giới thiệu các bạn ví dụ khi làm việc với XML:

static XDocument XmlUsingPlainCode()
{
    XDocument document = new XDocument
        (
            new XDeclaration("1.0", "utf-8", "yes"),
            new XComment("XML from plain code"),
            
            new XElement("Courses",
                new XElement("Course",
                    new XElement("Title", "XML Basics"),
                    new XElement("Duration", "15 min"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free")),
                new XElement("Course",
                    new XElement("Title", ".NET Core for Beginners"),
                    new XElement("Duration", "10 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free")))
        );

    return document;
}


Như bạn thấy, trong C# ta dễ dàng tạo được một XML bằng XDocument. Tiếp theo, XElement cho phép chúng ta khởi tạo một instance mới ngay bên trong XElement. Như vậy, ta có thể tạo được nhiều XElement  lồng nhau và đây là cách ta có thể tạo được một cấu trúc XML cụ thể.

Và dưới đây là kết quả sau khi chúng ta khởi tạo một XML:

<!--XML from plain code-->
<Courses>
  <Course>
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price>Free</Price>
  </Course>
  <Course>
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price>Free</Price>
  </Course>
</Courses>


Sử dụng XAttribute trong XML

Để bổ sung thông tin cho một element, chúng ta có thể dùng XAttribute, cụ thể ta update code trên thành như sau:

static XDocument XmlUsingPlainCode()
{
    XDocument document = new XDocument
        (
            new XDeclaration("1.0", "utf-8", "yes"),
            new XComment("XML from plain code"),
            
            new XElement("Courses",
                new XElement("Course",
                    new XAttribute("Id", 1),
                    new XElement("Title", "XML Basics"),
                    new XElement("Duration", "15 min"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency","USD"))),
                new XElement("Course",
                    new XAttribute("Id", 2),
                    new XElement("Title", ".NET Core for Beginners"),
                    new XElement("Duration", "10 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency", "DKK"))))
        );

    return document;
}


Trong mỗi XElement, chúng ta có thể khởi tạo một XAttribute mới gần giống như cách chúng ta đã làm với các element. Sau khi thêm các XAttribute, ta thu được kết quả như sau:

<!--XML from plain code-->
<Courses>
  <Course Id="1">
    <Title>XML Basics</Title>
    <Duration>15 min</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">Free</Price>
  </Course>
  <Course Id="2">
    <Title>.NET Core for Beginners</Title>
    <Duration>10 hours</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
</Courses>


Sử dụng LINQ để truy vấn tài liệu XML

LINQ là một cú pháp truy vấn thống nhất trong C# để truy xuất dữ liệu từ các nguồn và định dạng khác nhau, điều này lý tưởng để sử dụng nếu chúng ta muốn một số dữ liệu cụ thể trong tài liệu XML.

Bây giờ chúng ta sẽ có bài toán sau, chúng ta cần tạo một query để get tất cả các course element, với mỗi course chúng ta chia thành các mệnh giá khác nhau, khi course là Free chúng ta sẽ print "It is a free course", ngược lại ta in giá tiền kèm với currency của nó.

Như vậy, đầu tiền ta update lại mệnh giá của các course như sau:

static XDocument XmlUsingPlainCode()
{
    XDocument document = new XDocument
        (
            new XDeclaration("1.0", "utf-8", "yes"),
            new XComment("XML from plain code"),

            new XElement("Courses",
                // Free Course
                new XElement("Course",
                    new XAttribute("Id", 1),
                    new XElement("Title", "XML Basics"),
                    new XElement("Duration", "15 min"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency", "USD"))),

                // Paid Course
                new XElement("Course",
                    new XAttribute("Id", 2),
                    new XElement("Title", "Advanced MS SQL Queries"),
                    new XElement("Duration", "15 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", 12.95,
                        new XAttribute("Currency", "EUR"))),

                // Free Course
                new XElement("Course",
                    new XAttribute("Id", 2),
                    new XElement("Title", ".NET Core for Beginners"),
                    new XElement("Duration", "10 hours"),
                    new XElement("Instructor", "Christian Schou"),
                    new XElement("Price", "Free",
                        new XAttribute("Currency", "DKK"))))
        );

    return document;
}


Và bây giờ chúng ta sẽ viết một function sử dụng LINQ để thực hiện bài toán trên:

static void PerformLinqQueryOnXml(string docPath)
{
    XElement document = XElement.Load(docPath); // Load document as an XML Element

    var amountOfCourses = document.Elements("Course"); // Get the course elements into an enumerator

    Console.WriteLine("------ # Extract Courses In Document Using LINQ# ------\n");

    // Write out each course details to the console
    foreach (var course in amountOfCourses)
    {
        Console.WriteLine("### Course Details ###");
        Console.WriteLine($"Course: {course.Element("Title").Value}");
        Console.WriteLine($"Duration: {course.Element("Duration").Value}");
        Console.WriteLine($"Instructor: {course.Element("Instructor").Value}");

        if (course.Element("Price").Value == "Free")
        {
            Console.WriteLine($"Price: It's a free course\n");
        }
        else
        {
            Console.WriteLine($"Price: {course.Element("Price").Attribute("Currency").Value} {course.Element("Price").Value}\n");
        }
    }
}


Như vậy, ta có thể dễ dàng truy xuất đến element Price bằng các sử dụng method Element() cộng với .Value để lấy được giá trị bên trong element. Và sau cùng, ta chỉ việc viết condition phù hợp với bài toán trên và thu được kết quả như sau:

### Course Details ###
Course: XML Basics
Duration: 15 min
Instructor: Christian Schou
Price: It is a free course

### Course Details ###
Course: .NET Core for Beginners
Duration: 10 hours
Instructor: Christian Schou
Price: EUR 12.95

### Course Details ###
Course: .NET Core for Beginners
Duration: 10 hours
Instructor: Christian Schou
Price: It is a free course


Serialize XML

Khi chúng ta muốn serializing objects thì .NET framework đã cung cấp cho chúng ta một công cụ để có thể dễ dàng serialize bất kì object nào.

Để tiến hành các ví dụ dưới đây, chúng ta sẽ tạo ra 3 class sau:
  • Courses.cs
  • Course.cs
  • Price.cs 
Lần lượt các class được định nghĩa như sau:

Courses.cs:

using System.Collections.Generic;
using System.Xml.Serialization;

namespace XMLBasics.Models
{
    [XmlRoot("Courses")]
    public class Courses
    {
        [XmlElement(ElementName = "Academy")]
        public string Academy { get; set; }

        [XmlElement(ElementName = "Course")]
        public List<Course> CourseList { get; set; }

        public Courses()
        {
            CourseList = new List<Course>();
        }
    }
}


Course.cs
:

using System.Xml.Serialization;

namespace XMLBasics.Models
{
    [XmlRoot(ElementName = "Course")]
    public class Course
    {
    [XmlElement(ElementName = "Title")]
    public string Title { get; set; }

    [XmlElement(ElementName = "Duration")]
    public string Duration { get; set; }

    [XmlElement(ElementName = "Instructor")]
    public string Instructor { get; set; }

    [XmlElement(ElementName = "Price")]
    public Price Price { get; set; }

    [XmlAttribute(AttributeName = "Id")]
    public int Id { get; set; }

    [XmlText]
    public string Text { get; set; }

        public Course()
        {
        Price = new Price();
        }
    }
}


Price.cs:

using System.Xml.Serialization;

namespace XMLBasics.Models
{
    [XmlRoot(ElementName = "Price")]
    public class Price
    {
        [XmlAttribute(AttributeName = "Currency")]
        public string Currency { get; set; }

        [XmlText]
        public string Text { get; set; }
    }
}


Trên mỗi field, mỗi models, ta đã chỉ định các XML attributes. Như bạn có thể thấy chúng có các tên khác nhau vì ta muốn chúng hoạt động khác nhau khi serialize các đối tượng thành XML. 

Với mỗi class, ta luôn bắt đầu với việc định nghĩa XML root là gì ứng với một tên phần tử. Bạn có thể đặt tên cho model một cái gì đó và sau đó thay đổi tên của nó tại thời điểm serialization. Sau đó, ta chỉ định tất cả các phần tử thuộc thuộc tính cụ thể đó trong document.

Bây giờ chúng ta phải tạo một số objects mới và đặt chúng vào một list. List này sau đó sẽ được chuyển thành XML bằng thư viện System.Xml.Serialization. Sau cùng, chúng ta tạo một phương thức  SerializeToXml() với code sau:

static string SerializeToXml()
{
    string instructor = "Christian Schou";
    int i = 1;
    Random rand = new Random();

    // Create some courses
    Courses courses = new Courses { Academy = "Coding with Christian Schou",
        CourseList = new List<Course> {
            new Course
            {
                Title = "How to get started with MailKit",
                Duration = $"{rand.Next(1, 5)} hours and {rand.Next(0, 60)} minutes",
                Instructor = instructor,
                Price = new Price { Currency = "DKK", Text = "Free" }
            },
            new Course
            {
                Title = "Dapper with repository in ASP.NET",
                Duration = $"{rand.Next(1, 5)} hours and {rand.Next(0, 60)} minutes",
                Instructor = instructor,
                Price = new Price { Currency = "EUR", Text = "Free" }
            },
            new Course
            {
                Title = "How to create a WEB API",
                Duration = $"{rand.Next(1, 5)} hours and {rand.Next(0, 60)} minutes",
                Instructor = instructor,
                Price = new Price { Currency = "USD", Text = "19.95" }
            }
        }
    };

    // Set ID on each Course

    foreach (var course in courses.CourseList)
    {
        course.Id = i++;
    }

    XmlSerializer x = new XmlSerializer(courses.GetType()); // Get the exact runtime type of the current instance
    StringBuilder output = new StringBuilder();
    var writer = new StringWriter(output);
    x.Serialize(writer, courses);

    return output.ToString();

}


Method này sẽ tạo các console line để xác định dữ liệu khi chạy. Như bạn có thể thấy, ta đã thêm ba course làm đối tượng và thêm chúng vào danh sách được đặt tên courses dựa trên model Courses.cs.

Đối với mỗi course, chúng ta sẽ cung cấp một ID. Điều này có thể được thực hiện theo nhiều cách, nhưng cách đơn giản là dùng một vòng lặp foreach đơn giản giống như vòng lặp ta đã tạo ở trên. Nó chỉ cần lấy từng khóa học và cập nhật ID với số mà khóa học có trong danh sách.

Sau đó, chúng ta khởi tạo một instance mới của XmlSerializer nơi chỉ định loại danh sách có các khóa học. Cuối cùng, serialize content bằng cách sử dụng XmlSerializer.

Như vậy, chúng ta sẽ thu được kết quả như sau:

<?xml version="1.0" encoding="utf-16"?>
<Courses xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Academy>Coding with Christian Schou</Academy>
  <Course Id="1">
    <Title>How to get started with MailKit</Title>
    <Duration>4 hours and 42 minutes</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="DKK">Free</Price>
  </Course>
  <Course Id="2">
    <Title>Dapper with repository in ASP.NET</Title>
    <Duration>4 hours and 30 minutes</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="EUR">Free</Price>
  </Course>
  <Course Id="3">
    <Title>How to create a WEB API</Title>
    <Duration>4 hours and 38 minutes</Duration>
    <Instructor>Christian Schou</Instructor>
    <Price Currency="USD">19.95</Price>
  </Course>
</Courses>


Lời kết

Bây giờ bạn đã có kiến thức cơ bản về cách .NET cung cấp một cách đơn giản để làm việc với XML và cách dễ dàng để chuyển đổi các đối tượng thành XML và XML thành các đối tượng trong C# một cách nhanh chóng mà không cần phải viết hàng tấn code. Bạn cũng có khả năng đọc XML bằng LINQ tại XElement.

Nguồn tham khảo bài viết qua link dưới đây:
https://blog.christian-schou.dk/how-to-use-xml-with-c-sharp-a-beginners-guide/

Sắp tới, mình sẽ hướng dẫn các bước thực hiện kỹ thuật này một cách chi tiết như thực hiện CRUD data từ XML, những cách truy xuất XML node,... Mong các bạn tiếp tục theo dõi blog trong để đón chờ các bài viết tiếp theo.

Mong bài viết hữu ích, chúc các bạn thành công!
Hieu Ho.

Đăng nhận xét

Mới hơn Cũ hơn

TOGETHER

WE GROW