O parser SAX em Java fornece uma API para analisar documentos XML. O parser SAX é diferente do parser DOM porque não carrega o XML completo na memória e lê o documento XML sequencialmente.
Parser SAX
javax.xml.parsers.SAXParser
fornece método para analisar documento XML usando manipuladores de eventos. Esta classe implementa a interface XMLReader
e fornece versões sobrecarregadas dos métodos parse()
para ler documentos XML de arquivo, InputStream, SAX InputSource e URI de String. A análise real é feita pela classe Handler. Precisamos criar nossa própria classe de manipulador para analisar o documento XML. Precisamos implementar a interface org.xml.sax.ContentHandler
para criar nossas próprias classes de manipulador. Esta interface contém métodos de retorno de chamada que recebem notificação quando um evento ocorre. Por exemplo, StartDocument, EndDocument, StartElement, EndElement, CharacterData etc. org.xml.sax.helpers.DefaultHandler
fornece implementação padrão da interface ContentHandler e podemos estender esta classe para criar nosso próprio manipulador. É aconselhável estender esta classe porque podemos precisar de apenas alguns dos métodos para implementar. Estender esta classe manterá nosso código mais limpo e fácil de manter.
Exemplo de parser SAX
Vamos para o programa de exemplo de parser SAX agora, explicarei diferentes recursos em detalhes mais tarde. 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>
Então, temos um arquivo XML armazenado em algum lugar no sistema de arquivos e, ao examiná-lo, podemos concluir que ele contém uma lista de Funcionários. Cada Funcionário possui o atributo id
e os campos age
, name
, gender
e role
. Usaremos o parser SAX para analisar este XML e criar uma lista de objetos Funcionário. Aqui está o objeto Funcionário representando o elemento Funcionário do 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;
}
}
Vamos criar nossa própria classe de Manipulador de Parser SAX estendendo a classe 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 {
// Lista para armazenar objetos Funcionário
private List empList = null;
private Employee emp = null;
private StringBuilder data = null;
// Método getter para a lista de funcionários
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")) {
// Criar um novo Funcionário e colocá-lo no Mapa
String id = attributes.getValue("id");
// Inicializar objeto Funcionário e definir atributo id
emp = new Employee();
emp.setId(Integer.parseInt(id));
// Inicializar lista
if (empList == null)
empList = new ArrayList<>();
} else if (qName.equalsIgnoreCase("name")) {
// Definir valores booleanos para campos, serão usados na definição de variáveis do Funcionário
bName = true;
} else if (qName.equalsIgnoreCase("age")) {
bAge = true;
} else if (qName.equalsIgnoreCase("gender")) {
bGender = true;
} else if (qName.equalsIgnoreCase("role")) {
bRole = true;
}
// Criar o contêiner de dados
data = new StringBuilder();
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (bAge) {
// Elemento age, definir idade do Funcionário
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")) {
// Adicionar objeto Funcionário à lista
empList.add(emp);
}
}
@Override
public void characters(char ch[], int start, int length) throws SAXException {
data.append(new String(ch, start, length));
}
}
O MyHandler contém a lista do objeto Funcionário
como um campo com um método getter apenas. Os objetos Funcionário
estão sendo adicionados nos métodos do manipulador de eventos. Além disso, temos um campo Funcionário que será usado para criar um objeto Funcionário e, uma vez que todos os campos forem definidos, adicioná-lo à lista de funcionários.
Métodos do parser SAX para sobrescrever
Os métodos importantes para sobrescrever são startElement()
, endElement()
e characters()
. SAXParser
inicia a análise do documento, quando qualquer elemento de início é encontrado, o método startElement()
é chamado. Estamos sobrescrevendo este método para definir variáveis booleanas que serão usadas para identificar o elemento. Também estamos usando este método para criar um novo objeto Employee toda vez que o elemento de início do Employee é encontrado. Verifique como o atributo id é lido aqui para definir o campo id
do objeto Employee. O método characters()
é chamado quando dados de caracteres são encontrados pelo SAXParser dentro de um elemento. Note que o analisador SAX pode dividir os dados em vários pedaços e chamar o método characters()
várias vezes (Leia a documentação do método characters() da classe ContentHandler). Por isso, estamos usando o StringBuilder para manter esses dados usando o método append(). O endElement()
é o lugar onde usamos os dados do StringBuilder para definir as propriedades do objeto Employee e adicionar o objeto Employee à lista sempre que encontramos a tag de fim do Employee. Abaixo está o programa de teste que usa MyHandler
para analisar o XML acima para uma lista de objetos 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);
//Obter lista de Employees
List empList = handler.getEmpList();
//imprimir informações do funcionário
for(Employee emp : empList)
System.out.println(emp);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
}
Aqui está a saída do programa acima.
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
fornece métodos de fábrica para obter a instância do SAXParser
. Estamos passando o objeto File para o método parse juntamente com a instância de MyHandler para lidar com os eventos de retorno de chamada. O SAXParser é um pouco confuso no início, mas se você estiver trabalhando em um documento XML grande, ele fornece uma maneira mais eficiente de ler XML do que o DOM Parser. Isso é tudo para o SAX Parser em Java.
Você pode baixar o projeto do nosso Repositório do GitHub.
Referência: SAXParser, DefaultHandler
Source:
https://www.digitalocean.com/community/tutorials/java-sax-parser-example