CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Mục lục

Trang chủBlogJava SAX Parser: Hướng dẫ...
Java

Java SAX Parser: Hướng dẫn đọc và xử lý XML từng bước

5 phút đọc03/07/2025
CyStack Author
Bao Tran

Web Developer

0 lượt xem
Reading Time: 5 minutes

Bộ phân tích (parser) SAX trong Java cung cấp API để phân tích cú pháp các tài liệu XML. SAX parser khác với DOM parser ở chỗ nó không tải toàn bộ XML vào bộ nhớ mà sẽ đọc tài liệu theo tuần tự.

SAX parser trong Java

SAX Parser

javax.xml.parsers.SAXParser cung cấp phương thức để phân tích tài liệu XML bằng các bộ xử lý sự kiện (event handler). Class này triển khai interface XMLReader và cung cấp các phiên bản nạp chồng của phương thức parse() để đọc tài liệu XML từ file, input stream, input nguồn của SAX và URI dạng chuỗi.

Việc phân tích cú pháp thực tế được thực hiện bởi class Handler. Ta cần phải tạo class handler của riêng mình để phân tích tài liệu XML. Để làm điều này, ta cần triển khai interface ContentHandler. Nó chứa các hàm callback (gọi lại) sẽ nhận thông báo khi có một sự kiện xảy ra, ví dụ như StartDocument, EndDocument, StartElement, EndElement, CharacterData, v.v.

org.xml.sax.helpers.DefaultHandler cung cấp một triển khai mặc định của interface ContentHandler. Chúng ta có thể kế thừa (extend) class này để tạo handler riêng vì ta thường chỉ cần triển khai một vài phương thức mà thôi, giúp cho code của chúng ta gọn gàng và dễ bảo trì hơn.

Ví dụ SAX parser

Bây giờ, chúng ta hãy bắt đầu với ví dụ về SAX parser. Các tính năng chi tiết sẽ được giải thích chi tiết ở phần sau.



	
		29
		Pankaj
		Male
		Java Developer
	
	
		35
		Lisa
		Female
		CEO
	
	
		40
		Tom
		Male
		Manager
	
	
		25
		Meghna
		Female
		Manager
	

Giả sử ta có một file XML như trên (employees.xml) được lưu đâu đó trong hệ thống file. Nhìn vào đó, ta có thể thấy rằng nó chứa một danh sách các Employee. Mỗi Employee có một thuộc tính id và các trường name, genderrole.

Chúng ta sẽ dùng SAX parser để phân tích file này và tạo ra một danh sách các đối tượng Employee đại diện cho phần tử Employee từ file XML gốc.

package com.journaldev.xml;

public class Employee {
    private int id;
    private String name;
    private String gender;
    private int age;
    private String role;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getRole() {
        return role;
    }
    public void setRole(String role) {
        this.role = role;
    }
    
    @Override
    public String toString() {
        return "Employee:: ID="+this.id+" Name=" + this.name + " Age=" + this.age + " Gender=" + this.gender +
                " Role=" + this.role;
    }
    
}

Hãy cùng tạo class SAX Parser handler của riêng mình bằng cách kế thừa (extend) class DefaultHandler.

package com.journaldev.xml.sax;

import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.journaldev.xml.Employee;

public class MyHandler extends DefaultHandler {

	// List to hold Employees object
	private List empList = null;
	private Employee emp = null;
	private StringBuilder data = null;

	// getter method for employee list
	public List getEmpList() {
		return empList;
	}

	boolean bAge = false;
	boolean bName = false;
	boolean bGender = false;
	boolean bRole = false;

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

		if (qName.equalsIgnoreCase("Employee")) {
			// create a new Employee and put it in Map
			String id = attributes.getValue("id");
			// initialize Employee object and set id attribute
			emp = new Employee();
			emp.setId(Integer.parseInt(id));
			// initialize list
			if (empList == null)
				empList = new ArrayList<>();
		} else if (qName.equalsIgnoreCase("name")) {
			// set boolean values for fields, will be used in setting Employee variables
			bName = true;
		} else if (qName.equalsIgnoreCase("age")) {
			bAge = true;
		} else if (qName.equalsIgnoreCase("gender")) {
			bGender = true;
		} else if (qName.equalsIgnoreCase("role")) {
			bRole = true;
		}
		// create the data container
		data = new StringBuilder();
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (bAge) {
			// age element, set Employee age
			emp.setAge(Integer.parseInt(data.toString()));
			bAge = false;
		} else if (bName) {
			emp.setName(data.toString());
			bName = false;
		} else if (bRole) {
			emp.setRole(data.toString());
			bRole = false;
		} else if (bGender) {
			emp.setGender(data.toString());
			bGender = false;
		}
		
		if (qName.equalsIgnoreCase("Employee")) {
			// add Employee object to list
			empList.add(emp);
		}
	}

	@Override
	public void characters(char ch[], int start, int length) throws SAXException {
		data.append(new String(ch, start, length));
	}
}

MyHandler chứa một danh sách các đối tượng Employee dưới dạng một trường và chỉ có phương thức getter. Các đối tượng Employee được thêm vào danh sách bên trong các phương thức xử lý sự kiện. Ta cũng có một trường Employee được dùng để tạo đối tượng Employee. Một khi tất cả các trường của nó được thiết lập, đối tượng này sẽ được thêm vào danh sách.

Các phương thức của SAX parser cần ghi đè

Các phương thức quan trọng cần ghi đè là startElement(), endElement()characters(). Khi SAX parser chạy và gặp bất kỳ phần tử mở đầu nào, phương thức startElement() sẽ được gọi. Ta ghi đè phương thức này để thiết lập các biến boolean sẽ được dùng để xác định phần tử. Ta cũng dùng phương thức này để tạo một đối tượng Employee mới mỗi khi tìm thấy phần tử bắt đầu của Employee. Hãy xem cách thuộc tính id được đọc ở đây để thiết lập trường id cho đối tượng Employee.

Phương thức characters() được gọi khi SAX parser tìm thấy dữ liệu ký tự bên trong một phần tử. Lưu ý rằng SAX parser có thể chia dữ liệu thành nhiều đoạn (chunk) và gọi phương thức characters() nhiều lần (Hãy đọc tài liệu về phương thức characters() của class ContentHandler để hiểu về điều này). Đó là lý do tại sao ta dùng StringBuilder để lưu giữ dữ liệu này bằng phương thức append().

endElement() là nơi ta dùng dữ liệu từ StringBuilder để thiết lập các thuộc tính cho đối tượng Employee và thêm nó vào danh sách mỗi khi tìm thấy thẻ kết thúc của Employee trong file XML.

Dưới đây là chương trình test sử dụng MyHandler để phân tích file XML ở trên thành một danh sách các đối tượng Employee.

package com.journaldev.xml.sax;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import com.journaldev.xml.Employee;

public class XMLParserSAX {

    public static void main(String[] args) {
    SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
    try {
        SAXParser saxParser = saxParserFactory.newSAXParser();
        MyHandler handler = new MyHandler();
        saxParser.parse(new File("/Users/pankaj/employees.xml"), handler);
        //Get Employees list
        List empList = handler.getEmpList();
        //print employee information
        for(Employee emp : empList)
            System.out.println(emp);
    } catch (ParserConfigurationException | SAXException | IOException e) {
        e.printStackTrace();
    }
    }

}

Đây là output của nó.

Employee:: ID=1 Name=Pankaj Age=29 Gender=Male Role=Java Developer
Employee:: ID=2 Name=Lisa Age=35 Gender=Female Role=CEO
Employee:: ID=3 Name=Tom Age=40 Gender=Male Role=Manager
Employee:: ID=4 Name=Meghna Age=25 Gender=Female Role=Manager

SAXParserFactory cung cấp các phương thức factory để lấy một instance của SAXParser. Ta truyền đối tượng File vào phương thức parse() cùng với một instance của MyHandler để xử lý các sự kiện callback.

SAXParser ban đầu có thể hơi khó hiểu. Nhưng nếu bạn làm việc với một tài liệu XML lớn, nó sẽ cung cấp một cách đọc XML hiệu quả hơn DOM parser, giúp ứng dụng của bạn không bị quá tải. Bạn có thể tải project ví dụ ở trên từ GitHub để tìm hiểu thêm về công cụ này.

Về tác giả

Bao Tran
Bao TranWeb Developer

I’m passionate about web development and sharing my insights through articles, with over 8 years of experience. I hope these sharings inspire you and help build a strong web development community. @#@ Tôi đam mê phát triển web và chia sẻ những hiểu biết của mình thông qua các bài viết, với hơn 8 năm kinh nghiệm. Tôi hy vọng những chia sẻ này sẽ truyền cảm hứng cho các bạn và giúp xây dựng một cộng đồng phát triển web mạnh mẽ.

Cập nhật thông tin mới nhấtNhận các thông tin mới nhất về mối đe dọa, báo cáo an ninh mạng từ CyStack về hòm thư điện tử của bạn

Thảo luận (0)

Đăng nhập để thảo luận

Bài viết liên quan