Пример парсера Java SAX

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