Поиск по сайту:

Пример синтаксического анализатора Java SAX


SAX Parser в java предоставляет API для анализа XML-документов. Парсер SAX отличается от парсера DOM тем, что он не загружает полный XML в память и не читает XML-документ последовательно.

SAX-парсер

Пример парсера 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 Handler, расширяющий класс 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<Employee> empList = null;
	private Employee emp = null;
	private StringBuilder data = null;

	// getter method for employee list
	public List<Employee> 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 содержит список объекта Employee в виде поля только с методом получения. Объекты Employee добавляются в методы обработчика событий. Кроме того, у нас есть поле «Сотрудник», которое будет использоваться для создания объекта «Сотрудник», и после того, как все поля будут установлены, добавьте его в список сотрудников.

Методы парсера SAX для переопределения

Важными методами для переопределения являются startElement(), endElement() и characters(). SAXParser начинает разбор документа, при обнаружении любого начального элемента вызывается метод startElement(). Мы переопределяем этот метод, чтобы установить логические переменные, которые будут использоваться для идентификации элемента. Мы также используем этот метод для создания нового объекта Employee каждый раз, когда найден начальный элемент Employee. Проверьте, как здесь читается атрибут id, чтобы установить поле id объекта Employee. Метод characters() вызывается, когда SAXParser находит символьные данные внутри элемента. Обратите внимание, что синтаксический анализатор SAX может разделить данные на несколько фрагментов и вызвать метод characters() несколько раз (см. документацию по методу символов() класса ContentHandler). Вот почему мы используем StringBuilder для хранения этих данных с помощью метода append(). endElement() — это место, где мы используем данные StringBuilder для установки свойств объекта сотрудника и добавления объекта 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);
        //Get Employees list
        List<Employee> empList = handler.getEmpList();
        //print employee information
        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 методу разбора вместе с экземпляром MyHandler для обработки событий обратного вызова. SAXParser поначалу немного сбивает с толку, но если вы работаете с большим XML-документом, он обеспечивает более эффективный способ чтения XML, чем DOM Parser. Это все, что касается SAX Parser в Java.

Вы можете скачать проект из нашего репозитория GitHub.

Ссылка: Обработчик по умолчанию