Chúng ta đã cùng tìm hiểu làm thế nào để đọc tập tin XML sử dụng DOM trong Java ở bài viết trước, ở bài viết này mình giới thiệu với các bạn một cách khác để đọc tập tin XML nhanh hơn và sử dụng ít bộ nhớ hơn so với DOM, đó là sử dụng SAX trong Java các bạn nhé.
Thật vậy các bạn, đó là bởi vì cách làm việc của SAX khác nhiều so với DOM, nó không tải nội dung của tập tin XML lên trên bộ nhớ hay tạo bất kỳ đối tượng nào để nắm giữ thông tin của tập tin XML. Thay vào đó, nó sử dụng các phương thức callback của đối tượng org.xml.sax.helpers.DefaultHandler để đọc tập tin XML từ trên xuống dưới.
Để các bạn hiểu rõ hơn, mình có ví dụ sau nhé:
Nội dung của tập tin XML như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <students> <student n0='1'> <name>John</name> <code>12345</code> <age>19</age> </student> <student n0='2'> <name>Marry</name> <code>23456</code> <age>24</age> </student> </students> |
Ở đây, mình sử dụng một đối tượng Student để lưu thông tin đã đọc được của tập tin XML, nội dung của lớp Student như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package com.huongdanjava.sax; public class Student { private String name; private String age; private String code; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", code=" + code + "]"; } } |
Để đọc tập tin XML sử dụng SAX, đầu tiên chúng ta sẽ sử dụng các phương thức callback trong đối tượng DefaultHandler để đọc nội dung tập tin XML. Các bạn hãy tưởng tượng, chúng ta có tập tin XML và chúng ta sẽ đọc nội dung của nó từ trên xuống dưới, từ ngoài vào trong theo thứ tự phân cấp.
Đối tượng DefaultHandler có các phương thức callback sau:
- startDocument() và endDocument(): 2 phương thức này sẽ được gọi tới khi chúng ta bắt đầu đọc và kết thúc đọc tập tin XML.
- startElement() và endElement(): 2 phương thức này được gọi khi chúng ta bắt đầu đọc một thẻ trong tập tin XML.
- characters(): phương thức này được gọi khi chúng ta đọc nội dung giữa hai thẻ đóng mở của tập tin XML.
Mình sẽ viết đối tượng DefaultHandler để đọc tập tin XML students.xml như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
final List<Student> students = new ArrayList<Student>(); DefaultHandler defaultHandler = new DefaultHandler() { Student student = null; boolean isName = false; boolean isCode = false; boolean isAge = false; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("student")) { // Bắt đầu đọc thẻ student student = new Student(); } else if (qName.equals("name")) { // Bắt đầu đọc thẻ name isName = true; } else if (qName.equals("code")) { // Bắt đầu đọc thẻ code isCode = true; } else if (qName.equals("age")) { // Bắt đầu đọc thẻ age isAge = true; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { // Lấy nội dung bên trong của một thẻ String value = new String(ch, start, length); // Và gán giá trị vào đối tượng Student if (isName) { student.setName(value); isName = false; } else if (isCode) { student.setCode(value); isCode = false; } else if (isAge) { student.setAge(value); isAge = false; } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // Khi đọc đến thẻ đóng của thẻ student, lúc này chúng ta có thể thêm đối tượng Student hiện tại vào trong đối tượng students. if (qName.equals("student")) { students.add(student); } } }; |
Chúng ta đã có đối tượng handler rồi, bây giờ chúng ta sẽ khởi tạo đối tượng SAXParser để sử dụng đối tượng handler đọc tập tin XML.
1 2 |
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxParserFactory.newSAXParser(); |
Tiếp theo, chúng ta sẽ gọi phương thức parse() của đối tượng SAXParser để bắt đầu đọc tập tin XML.
1 |
saxParser.parse("students.xml", defaultHandler); |
Xem danh sách sinh viên sau khi đọc:
1 |
System.out.println(students.toString()); |
Kết quả:
Code đầy đủ để các bạn tham khảo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
package com.huongdanjava.sax; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class SAXExample { public static void main(String[] args) { try { SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxParserFactory.newSAXParser(); final List<Student> students = new ArrayList<Student>(); DefaultHandler defaultHandler = new DefaultHandler() { Student student = null; boolean isName = false; boolean isCode = false; boolean isAge = false; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("student")) { // Bắt đầu đọc thẻ student student = new Student(); } else if (qName.equals("name")) { // Bắt đầu đọc thẻ name isName = true; } else if (qName.equals("code")) { // Bắt đầu đọc thẻ code isCode = true; } else if (qName.equals("age")) { // Bắt đầu đọc thẻ age isAge = true; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { // Lấy nội dung bên trong của một thẻ String value = new String(ch, start, length); // Và gán giá trị vào đối tượng Student if (isName) { student.setName(value); isName = false; } else if (isCode) { student.setCode(value); isCode = false; } else if (isAge) { student.setAge(value); isAge = false; } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // Khi đọc đến thẻ đóng của thẻ student, lúc này chúng ta có thể thêm đối tượng Student hiện tại vào trong đối tượng students. if (qName.equals("student")) { students.add(student); } } }; saxParser.parse("students.xml", defaultHandler); System.out.println(students.toString()); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } |