¿Cómo leer un xml con Java utilizando Sax?


Procesar xml’s en aplicaciones es una tarea común, en este ejemplo se explicará como utilizar SAX (Simple API for XML), Sax no utiliza el DOM para procesar el xml este utiliza notificaciones (Callbacks) sobre el elemento que se esta procesando en orden iniciando por la parte de arriba del documento y terminando con la etiqueta que cierra el documento.

Archivo a procesar

El archivo que se procesará en este ejemplo será un xml que contiene la información de desayunos en un restaurant, este contiene el nombre, descripción, precio y calorías. La aplicación leerá el xml y generará una lista de objetos java con la información. A continuación se muestra el xml a procesar.

<?xml version="1.0"?>
<breakfast_menu>
	<food>
		<name>Belgian Waffles</name>
		<price>5.95</price>
		<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
		<calories>650</calories>
	</food>
	<food>
		<name>Strawberry Belgian Waffles</name>
		<price>7.95</price>
		<description>Light Belgian waffles covered with strawberries and whipped cream</description>
		<calories>900</calories>
	</food>
	<food>
		<name>Berry-Berry Belgian Waffles</name>
		<price>8.95</price>
		<description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
		<calories>900</calories>
	</food>
	<food>
		<name>French Toast</name>
		<price>4.50</price>
		<description>Thick slices made from our homemade sourdough bread</description>
		<calories>600</calories>
	</food>
	<food>
		<name>Homestyle Breakfast</name>
		<price>6.95</price>
		<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
		<calories>950</calories>
	</food>
</breakfast_menu>

Crear modelo de la aplicación

Antes de iniciar escribiendo la lógica de la aplicación, iniciaremos creando las clases que nos ayudarán para almacenar la información  y los nombres de los elementos que existe en el xml. Para esto crearemos 2 componentes una enumeración que contendrá el nombre de los elementos del xml y un POJO que contendrá la información que se lea del mismo.

/**
 *
 */
package com.raidentrance.model;

/**
 * @author raidentrance
 *
 */
public enum BreakfastElement {
	FOOD("food"), NAME("name"), PRICE("price"), DESCRIPTION("description"), CALORIES("calories");

	private String name;

	private BreakfastElement(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

}

BreakfastElement contiene los nombres de las etiquetas que nos interesa procesar del xml.

/**
 *
 */
package com.raidentrance.model;

/**
 * @author maagapi
 *
 */
public class Food {

	private String name;
	private double price;
	private String description;
	private int calories;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public int getCalories() {
		return calories;
	}

	public void setCalories(int calories) {
		this.calories = calories;
	}

}

Food contiene los valores que se leerán del xml.

Procesando el xml

Para procesar un xml con SAX es necesario crear un handler, para hacerlo se creará una clase que herede de DefaultHandler y se sobre escribirán  los siguientes métodos:

  • public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
  • public void characters(char[] ch, int start, int length) throws SAXException

  • public void endElement(String uri, String localName, String qName) throws SAXException

  • El método startElement se llamará al inicio de un elemento
  • El método characters  se llamará cuando se encuentre la información dentro de un elemento
  • El método endElement se llamará al final de un elemento
/**
 *
 */
package com.raidentrance.handler;

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.raidentrance.model.BreakfastElement;
import com.raidentrance.model.Food;

/**
 * @author raidentrance
 *
 */
public class BreakFastHandler extends DefaultHandler {

	private boolean name;
	private boolean price;
	private boolean description;
	private boolean calories;

	private Food currentFood = new Food();
	private List<Food> breakfast = new ArrayList<>();

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if (qName.equals(BreakfastElement.NAME.getName())) {
			name = true;
		}
		if (qName.equals(BreakfastElement.PRICE.getName())) {
			price = true;
		}
		if (qName.equals(BreakfastElement.DESCRIPTION.getName())) {
			description = true;
		}
		if (qName.equals(BreakfastElement.CALORIES.getName())) {
			calories = true;
		}
	}

	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		if (name) {
			currentFood.setName(new String(ch, start, length));
			name = false;
		}
		if (price) {
			currentFood.setPrice(Double.parseDouble(new String(ch, start, length)));
			price = false;
		}
		if (description) {
			currentFood.setDescription(new String(ch, start, length));
			description = false;
		}
		if (calories) {
			currentFood.setCalories(Integer.parseInt(new String(ch, start, length)));
			calories = false;
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (qName.equals(BreakfastElement.FOOD.getName())) {
			breakfast.add(currentFood);
			currentFood = new Food();
		}
	}

	public List<Food> getBreakfast() {
		return breakfast;
	}

}

La clase BreakFastHandler implementa la lógica necesaria para leer los elementos del xml, crear POJO’s con la información y agregarlos a una lista con la información.

Creando el parser

El último paso para mostrar la información es crear un parser el cual invocará el handler que creamos y desplegará la respuesta en la consola.

/**
 *
 */
package com.raidentrance.parser;

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.raidentrance.handler.BreakFastHandler;
import com.raidentrance.model.Food;

/**
 * @author maagapi
 *
 */
public class BreakfastParser {
	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser saxParser = factory.newSAXParser();
		BreakFastHandler handler = new BreakFastHandler();
		saxParser.parse("src/main/resources/menu.xml", handler);
		List<Food> list = handler.getBreakfast();
		for (Food food : list) {
			System.out.println("Name: " + food.getName());
			System.out.println("Description: " + food.getDescription());
			System.out.println("Price: " + food.getPrice());
			System.out.println("Calories: " + food.getCalories());
			System.out.println("---------------------------------------------------------------------------------------------");
		}
	}
}

Salida

A continuación se muestra la salida al ejecutar la aplicación:

Name: Belgian Waffles
Description: Two of our famous Belgian Waffles with plenty of real maple syrup
Price: 5.95
Calories: 650
---------------------------------------------------------------------------------------------
Name: Strawberry Belgian Waffles
Description: Light Belgian waffles covered with strawberries and whipped cream
Price: 7.95
Calories: 900
---------------------------------------------------------------------------------------------
Name: Berry-Berry Belgian Waffles
Description: Light Belgian waffles covered with an assortment of fresh berries and whipped cream
Price: 8.95
Calories: 900
---------------------------------------------------------------------------------------------
Name: French Toast
Description: Thick slices made from our homemade sourdough bread
Price: 4.5
Calories: 600
---------------------------------------------------------------------------------------------
Name: Homestyle Breakfast
Description: Two eggs, bacon or sausage, toast, and our ever-popular hash browns
Price: 6.95
Calories: 950
---------------------------------------------------------------------------------------------

Puedes encontrar el código completo del ejemplo en el siguiente enlace: https://github.com/raidentrance/sax-example

Autor: Alejandro Agapito Bautista

Twitter: @raidentrance

Contacto:raidentrance@gmail.com

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s