Esempio Parser SAX Java

Il parser SAX in java fornisce API per analizzare i documenti XML. Il parser SAX è diverso dal parser DOM perché non carica l’intero XML in memoria e legge il documento xml in sequenza.

Parser SAX

javax.xml.parsers.SAXParser fornisce un metodo per analizzare un documento XML utilizzando gli event handlers. Questa classe implementa l’interfaccia XMLReader e fornisce versioni sovraccaricate dei metodi parse() per leggere il documento XML da File, InputStream, SAX InputSource e String URI. Il parsing effettivo viene eseguito dalla classe Handler. Abbiamo bisogno di creare la nostra classe handler per analizzare il documento XML. Dobbiamo implementare l’interfaccia org.xml.sax.ContentHandler per creare le nostre classi handler. Questa interfaccia contiene metodi di callback che ricevono una notifica quando si verifica un evento. Ad esempio StartDocument, EndDocument, StartElement, EndElement, CharacterData, ecc. org.xml.sax.helpers.DefaultHandler fornisce un’implementazione predefinita dell’interfaccia ContentHandler e possiamo estendere questa classe per creare il nostro handler. È consigliabile estendere questa classe perché potremmo aver bisogno di implementare solo alcuni dei metodi. Estendere questa classe manterrà il nostro codice più pulito e manutenibile.

Esempio di parser SAX

Passiamo ora all’esempio di programma del parser SAX, spiegherò in dettaglio le diverse funzionalità in seguito. 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>

Abbiamo un file XML archiviato in un sistema di file e, guardandolo, possiamo dedurre che contiene una lista di dipendenti. Ogni dipendente ha un attributo “id” e i campi “età”, “nome”, “genere” e “ruolo”. Utilizzeremo un parser SAX per analizzare questo XML e creare una lista di oggetti Dipendente. Ecco l’oggetto Dipendente che rappresenta l’elemento Dipendente dell’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;
    }
    
}

Creiamo la nostra classe Handler del parser SAX estendendo la 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 per contenere gli oggetti Dipendente
	private List empList = null;
	private Employee emp = null;
	private StringBuilder data = null;

	// Metodo getter per la lista dei dipendenti
	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")) {
			// Creare un nuovo Dipendente e inserirlo nella mappa
			String id = attributes.getValue("id");
			// Inizializzare l'oggetto Dipendente e impostare l'attributo id
			emp = new Employee();
			emp.setId(Integer.parseInt(id));
			// Inizializzare la lista
			if (empList == null)
				empList = new ArrayList<>();
		} else if (qName.equalsIgnoreCase("name")) {
			// Impostare i valori booleani per i campi, saranno utilizzati per impostare le variabili Dipendente
			bName = true;
		} else if (qName.equalsIgnoreCase("age")) {
			bAge = true;
		} else if (qName.equalsIgnoreCase("gender")) {
			bGender = true;
		} else if (qName.equalsIgnoreCase("role")) {
			bRole = true;
		}
		// Creare il contenitore dei dati
		data = new StringBuilder();
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (bAge) {
			// Elemento età, impostare l'età del Dipendente
			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")) {
			// Aggiungere l'oggetto Dipendente alla lista
			empList.add(emp);
		}
	}

	@Override
	public void characters(char ch[], int start, int length) throws SAXException {
		data.append(new String(ch, start, length));
	}
}

MyHandler contiene la lista degli oggetti Dipendente come campo con solo un metodo getter. Gli oggetti Dipendente vengono aggiunti nei metodi event handler. Inoltre, abbiamo un campo Dipendente che verrà utilizzato per creare un oggetto Dipendente e una volta impostati tutti i campi, verrà aggiunto alla lista dei dipendenti.

Metodi del parser SAX da sovrascrivere

I metodi importanti da sovrascrivere sono startElement(), endElement() e characters(). SAXParser inizia a analizzare il documento, quando viene trovato qualsiasi elemento di inizio, viene chiamato il metodo startElement(). Stiamo sovrascrivendo questo metodo per impostare le variabili booleane che verranno utilizzate per identificare l’elemento. Stiamo anche utilizzando questo metodo per creare un nuovo oggetto Employee ogni volta che viene trovato l’elemento di inizio Employee. Verifica come viene letto l’attributo id qui per impostare il campo id dell’oggetto Employee. Il metodo characters() viene chiamato quando il parser SAX trova dati di carattere all’interno di un elemento. Si noti che il parser SAX può dividere i dati in più frammenti e chiamare il metodo characters() più volte (leggere la documentazione del metodo characters() della classe ContentHandler). Ecco perché stiamo usando StringBuilder per conservare questi dati utilizzando il metodo append(). Il metodo endElement() è il punto in cui utilizziamo i dati di StringBuilder per impostare le proprietà dell’oggetto employee e aggiungere l’oggetto Employee alla lista ogni volta che viene trovato il tag di fine Employee. Di seguito è riportato il programma di test che utilizza MyHandler per analizzare l’XML precedente in una lista di oggetti 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);
        // Ottenere la lista dei dipendenti
        List empList = handler.getEmpList();
        // stampare le informazioni sul dipendente
        for(Employee emp : empList)
            System.out.println(emp);
    } catch (ParserConfigurationException | SAXException | IOException e) {
        e.printStackTrace();
    }
    }

}

Ecco l’output del programma precedente.

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 fornisce metodi di fabbrica per ottenere l’istanza di SAXParser. Stiamo passando un oggetto File al metodo parse insieme all’istanza di MyHandler per gestire gli eventi di callback. SAXParser è un po’ confuso all’inizio, ma se stai lavorando su un documento XML grande, fornisce un modo più efficiente per leggere l’XML rispetto al parser DOM. Questo è tutto per il parser SAX in Java.

Puoi scaricare il progetto dal nostro Repository GitHub.

Riferimento: SAXParser, DefaultHandler

Source:
https://www.digitalocean.com/community/tutorials/java-sax-parser-example