SAX Парсер в Java предоставляет API для разбора XML-документов. SAX парсер отличается от DOM парсера, потому что он не загружает весь XML в память и читает документ последовательно.
SAX Парсер
javax.xml.parsers.SAXParser
предоставляет метод для разбора XML-документа с использованием обработчиков событий. Этот класс реализует интерфейс XMLReader
и предоставляет перегруженные версии методов parse()
для чтения XML-документа из файла, потока ввода, SAX InputSource и строки URI. Фактический разбор выполняется классом Handler. Нам нужно создать собственный класс обработчика для разбора XML-документа. Мы должны реализовать интерфейс org.xml.sax.ContentHandler
для создания собственных классов обработчиков. Этот интерфейс содержит методы обратного вызова, которые получают уведомление, когда происходит событие. Например, StartDocument, EndDocument, StartElement, EndElement, CharacterData и т. д. org.xml.sax.helpers.DefaultHandler
предоставляет реализацию по умолчанию интерфейса ContentHandler, и мы можем расширить этот класс, чтобы создать собственный обработчик. Рекомендуется расширять этот класс, потому что нам может потребоваться реализовать только несколько методов. Расширение этого класса поможет сохранить наш код чистым и поддерживаемым.
Пример парсера SAX
Давайте перейдем к программе примера парсера SAX, я объясню различные особенности подробнее позже. employees.xml
<?xml version="1.0" encoding="UTF-8"?>
<Employees>
<Employee id="1">
<age>29</age>
<name>Pankaj</name>
<gender>Male</gender>
<role>Java Developer</role>
</Employee>
<Employee id="2">
<age>35</age>
<name>Lisa</name>
<gender>Female</gender>
<role>CEO</role>
</Employee>
<Employee id="3">
<age>40</age>
<name>Tom</name>
<gender>Male</gender>
<role>Manager</role>
</Employee>
<Employee id="4">
<age>25</age>
<name>Meghna</name>
<gender>Female</gender>
<role>Manager</role>
</Employee>
</Employees>
Итак, у нас есть XML-файл, сохраненный где-то в файловой системе, и, глядя на него, мы можем заключить, что он содержит список сотрудников. Каждый сотрудник имеет атрибут id
и поля age
, name
, gender
и role
. Мы будем использовать SAX-парсер для разбора этого XML и создания списка объектов Employee. Вот объект Employee, представляющий элемент Employee из XML.
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;
}
}
Создадим собственный класс обработчика SAX Parser, расширив класс 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 {
// Список для хранения объектов Employee
private List empList = null;
private Employee emp = null;
private StringBuilder data = null;
// Метод доступа к списку сотрудников
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")) {
// Создать новый объект Employee и поместить его в Map
String id = attributes.getValue("id");
// Инициализировать объект Employee и установить атрибут id
emp = new Employee();
emp.setId(Integer.parseInt(id));
// Инициализировать список
if (empList == null)
empList = new ArrayList<>();
} else if (qName.equalsIgnoreCase("name")) {
// Установить логические значения для полей, которые будут использоваться при установке переменных Employee
bName = true;
} else if (qName.equalsIgnoreCase("age")) {
bAge = true;
} else if (qName.equalsIgnoreCase("gender")) {
bGender = true;
} else if (qName.equalsIgnoreCase("role")) {
bRole = true;
}
// Создать контейнер данных
data = new StringBuilder();
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (bAge) {
// Элемент age, установить возраст Employee
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")) {
// Добавить объект Employee в список
empList.add(emp);
}
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
data.append(new String(ch, start, length));
}
}
МойОбработчик содержит список объектов Employee
в качестве поля только с методом доступа. Объекты Employee
добавляются в методы обработчика событий. Кроме того, у нас есть поле Employee, которое будет использоваться для создания объекта Employee, и как только все поля будут установлены, он будет добавлен в список сотрудников.
Методы SAX-парсера для переопределения
Важные методы для переопределения – это startElement()
, endElement()
и characters()
. SAXParser
начинает разбор документа, когда найден любой начальный элемент, вызывается метод startElement()
. Мы переопределяем этот метод, чтобы установить логические переменные, которые будут использоваться для идентификации элемента. Мы также используем этот метод для создания нового объекта Employee каждый раз, когда найден элемент Employee. Проверьте, как атрибут id считывается здесь для установки поля id
объекта Employee. Метод characters()
вызывается, когда SAXParser обнаруживает символьные данные внутри элемента. Обратите внимание, что SAX-анализатор может разбивать данные на несколько фрагментов и вызывать метод characters()
несколько раз (см. документацию метода characters() класса ContentHandler). Поэтому мы используем StringBuilder для сохранения этих данных с помощью метода append(). endElement()
– это место, где мы используем данные StringBuilder для установки свойств объекта employee и добавления объекта Employee в список всякий раз, когда мы найдем конечный тег элемента Employee. Ниже приведена тестовая программа, которая использует MyHandler
для разбора вышеуказанного XML в список объектов 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);
// Получить список сотрудников
List empList = handler.getEmpList();
// печать информации о сотруднике
for(Employee emp : empList)
System.out.println(emp);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
Вот результат выполнения вышеуказанной программы.
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
предоставляет методы фабрики для получения экземпляра SAXParser
. Мы передаем объект File в метод parse вместе с экземпляром MyHandler для обработки событий обратного вызова. SAXParser немного запутан в начале, но если вы работаете с большим XML-документом, он предоставляет более эффективный способ чтения XML, чем DOM Parser. Вот и все для SAX Parser в Java.
Вы можете скачать проект из нашего репозитория на GitHub.
Ссылка: SAXParser, DefaultHandler
Source:
https://www.digitalocean.com/community/tutorials/java-sax-parser-example