Wednesday, May 27, 2015

Đọc, ghi và parse dữ liệu XML trong NodeJS với xml2js


Chào các bạn,

Để đọc, ghi dữ liệu dưới định dạng XML ra đối tượng, trên javascript và NodeJS có rất nhiều plugin hay. Tuy nhiên, hôm nay mình sẽ giới thiệu một module sử dụng phổ biến trong NodeJS là xml2js.

1. Đọc dữ liệu XML và parse ra đối tượng để sử dụng.

Giả sử chúng ta có file employees.xml với nội dung như sau:

<?xml version="1.0" encoding="UTF-8" ?>
<employees>
    <employee>
        <id>1</id>
        <firstName>Leonardo</firstName>
        <lastName>DiCaprio</lastName>
        <photo>https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp4LaZFNT21_cClGHcnXd24XSGCXT4T17wszoZi-avLGGT047GDcDv3n45nQ9I4QItFweKDU4XZYTT-sK5bieeLOVJniXQ_su5bue-Ung_zszA5s1poJQTNP4hL-Wp2rb909QXikKwicg/s200/Leonardo+Dicaprio7.jpg</photo>
    </employee>
    <employee>
        <id>2</id>
        <firstName>Johnny</firstName>
        <lastName>Depp</lastName>
        <photo>http://4.bp.blogspot.com/_xR71w9-qx9E/SrAz--pu0MI/AAAAAAAAC38/2ZP28rVEFKc/s200/johnny-depp-pirates.jpg</photo>
    </employee>
    <employee>
        <id>3</id>
        <firstName>Hritik</firstName>
        <lastName>Roshan</lastName>
        <photo>http://thewallmachine.com/files/1411921557.jpg</photo>
    </employee>
</employees>

Chúng ta sẽ làm một đoạn code, đọc file này và in ra màn hình tên của các employee trong list ra nha.
Tại thư mục NodeEx/XMLParser/ ta tạo file XML có nội dung như trên. (Dữ liệu mẫu mình lấy từ sample ở đây)
Đưa con trỏ về thư mục này và cài đặt module xml2js bằng cú pháp sau:
$npm install xml2js
Tạo một file có tên xmlparser.js và chúng ta bắt đầu code nào.
Đầu tiên là khai báo các biến require cần thiết, vì chúng ta cần đến Module FileSytem để đọc, ghi file nên cần khai báo thêm biến var fs = require('fs'); 
var fs = require('fs'),
    xml2js = require('xml2js');
Tiếp theo là việc sử dụng fs để đọc file. Để đọc file xml, đơn giản chúng ta sử dụng hàm sau:
fs.readFile(file_name, 'utf8',function(err, data) {
    if (err) {
        //handle error
    }    else{
        //process data
        //parse data to object and print out to console
    }    
 });
Chú ý ở option thứ 2, là để chỉ ra rằng thao tác đọc file hỗ trợ định dạng utf8, có thể không có cũng được Tuy nhiên mình đưa vào để có trường hợp các bạn sử dụng file tiếng việt chẳng hạn sẽ cần, và cũng để chúng ta sẽ áp dụng cho bài viết sau nữa về ví dụ xây dựng một trang blog đơn giản.
Để handle lỗi, các bạn có thể ghi log, send alert, hoặc đơn giản là out ra console. Lỗi có thể xảy ra trong các trường hợp không tìm thầy file, file không có quyền truy cập, file bị corruptered...
Nếu không lỗi, chúng ta tiếp đến bước xử lý dữ liệu.
xml2js cung cấp đối tượng parser, và cung cấp hàm parseString dữ liệu data xml của chúng ta ra thành đối tượng theo cấu trúc của xml.
var parser = new xml2js.Parser();
parser.parseString(data, function (err, result) {});
data là dữ liệu đầu vào cần xử lý, err là đển handle lỗi và result là đối tượng kết quả của hàm này.
Dựa vào file dữ liệu xml ở trên, ta dễ nhận thấy rằng result chính là đối tượng employees, chứa danh sách các employee. Để truy xuất đến các nội dung bên trong, đơn giản chỉ cần là object[attribute name].
Phần handle lỗi bao gồm các lỗi về parse như: lỗi thiếu đóng mở tag, lỗi không well-formed của xml.
Cuối cùng, sử dụng hàm console.log để out ra name của các employee thông qua vòng lặp.
Tổng hợp lại từ trên, ta có đoạn code hoàn chỉnh như sau:
var fs = require('fs'),
    xml2js = require('xml2js');
    
fs.readFile('employees.xml', 'utf8',function(err, data) {
    if (err) {
        //handle error
        console.log(err.message);
    }else{
        //process data
        //parse data to object and print out to console
        var parser = new xml2js.Parser();
        parser.parseString(data, function (err, result) {
            if (err) {  
                    console.log(err.message); return;
                }
            var arr = (result['employees'])['employee'];
            for (var i = 0; i < arr.length; i++) {
                console.log(arr[i]['firstName']);
            }
        });
    }
});
Giờ chúng ta chạy chương trình và xem kết quả nào:
$node xmlparser.js
Kết quả nè:

 Well, tưởng phức tạp, hóa ra cũng thường thôi.
Giờ ta có thể tùy biến một chút, sử dụng
http = require('http');

JSON.stringify(result);
để xuất ra thành server khi có request xem sao nhé.
var fs = require('fs'),
    xml2js = require('xml2js'),
    http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain;charset=utf-8'});
    fs.readFile('employees.xml', 'utf8',function(err, data) {
        if (err) {
            //handle error
            console.log(err.message);
        }else{
            //process data
            //parse data to object and print out to console
            var parser = new xml2js.Parser();
            parser.parseString(data, function (err, result) {
                if (err) {  
                    console.log(err.message);
                }else{
                    res.end( JSON.stringify(result));
                }
                
            });
        }
    });
}).listen(8080); 
Chạy server, và duyệt http://localhost:8080/ các bạn sẽ nhận được một kết quả vô cùng dễ thương như sau phải không ạ?
{
    "employees": {
        "employee": [{
            "id": ["1"],
            "firstName": ["Leonardo"],
            "lastName": ["DiCaprio"],
            "photo": ["https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhp4LaZFNT21_cClGHcnXd24XSGCXT4T17wszoZi-avLGGT047GDcDv3n45nQ9I4QItFweKDU4XZYTT-sK5bieeLOVJniXQ_su5bue-Ung_zszA5s1poJQTNP4hL-Wp2rb909QXikKwicg/s200/Leonardo+Dicaprio7.jpg"]
        }, {
            "id": ["2"],
            "firstName": ["Johnny"],
            "lastName": ["Depp"],
            "photo": ["http://4.bp.blogspot.com/_xR71w9-qx9E/SrAz--pu0MI/AAAAAAAAC38/2ZP28rVEFKc/s200/johnny-depp-pirates.jpg"]
        }, {
            "id": ["3"],
            "firstName": ["Hritik"],
            "lastName": ["Roshan"],
            "photo": ["http://thewallmachine.com/files/1411921557.jpg"]
        }]
    }
}
Ok. Như vậy chúng ta đã có thể đơn giản viết một service bằng Nodejs, mỗi khi có request, sẽ gửi trả về danh sách các employee rồi.

2. Ghi đối tượng JSON thành file XML

Để thực hiện việc này xml2js cung cấp cho chúng ta đối tượng Builder với hàm buildObject để thực hiện chuyển đổi đối tượng từ chuỗi JSON sang chuỗi XML. Từ đây dùng hàm writeFile của filesytem để lưu file.
Giả sử chúng ta có danh sách các person như sau:
var people = {'person':[{'id':1,'name':'Son','age':18,'email':'sonnt@gmail.com'},{'id':2,'name':'Nhung','age':16,'email':'nhungtran@gmail.com'}]};
Nhiệm vụ là chúng ta lưu danh sách này vào file people.xml danh sách các person này theo đúng định dạng, thứ tự của thuộc tính. Sử dụng đối tượng như đã nói trên, ta có code đầy đủ như sau:
var fs = require('fs'),
    xml2js = require('xml2js');
    
var people = {'person':[{'id':1,'name':'Son','age':18,'email':'sonnt@gmail.com'},{'id':2,'name':'Nhung','age':16,'email':'nhungtran@gmail.com'}]};
var builder = new xml2js.Builder({rootName:'people'});
people = builder.buildObject(people);
fs.writeFile("people.xml", people, function(err) {
    if(err) {
        return console.log(err);
    }
    console.log("The file was saved!");
}); 
Chú ý ta cần set rootName để có đối tượng cha là danh sách. Nếu không cần thiết, các bạn bỏ đi cũng ok.
Các bạn chạy file và xem kết quả như thế nào nhé.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<people>
  <person>
    <id>1</id>
    <name>Son</name>
    <age>18</age>
    <email>sonnt@gmail.com</email>
  </person>
  <person>
    <id>2</id>
    <name>Nhung</name>
    <age>16</age>
    <email>nhungtran@gmail.com</email>
  </person>
</people>
Hôm nay đến đây là đủ. Bài tập nâng cao cho các bạn hôm nay là khi truyền vào id ở querystring, thì bạn sẽ trả về đúng employee có id đó. Hãy làm và để lại kết quả ở phần comment nhé.
Share this post
  • Share to Facebook
  • Share to Twitter
  • Share to Google+
  • Share to Stumble Upon
  • Share to Evernote
  • Share to Blogger
  • Share to Email
  • Share to Yahoo Messenger
  • More...
 
Posts RSSComments RSSBack to top
© 2011 Tự học NodeJS ∙ Designed by BlogThietKe
Released under Creative Commons 3.0 CC BY-NC 3.0