1. Знакомство с потоковым парсингом
В Java исторически сложились два подхода к работе с XML.
Мы уже в курсе, что DOM (Document Object Model) строит дерево документа в памяти. Удобно перемещаться по элементам и редактировать их, но для больших файлов это слишком затратно: память быстро заканчивается.
В свою очередь SAX (Simple API for XML) обрабатывает файл последовательно и вызывает события при встрече с тегами. Это экономно по памяти, можно работать с огромными документами. Но писать обработчики неудобно, а вернуться назад по структуре невозможно.
StAX (Streaming API for XML) появился как компромисс. Он тоже потоковый, как SAX, но даёт программисту больше контроля: мы сами «тянем» события из потока, когда это нужно. Такой подход называют pull-парсингом, и он позволяет писать более понятный и гибкий код.
Введение в StAX
StAX (Streaming API for XML) — это современный потоковый парсер XML для Java, появившийся в JDK 6+.
Главная идея: pull-парсинг («тянущий» парсер).
В отличие от SAX, где парсер сам вызывает ваши методы (push-модель), в StAX вы сами управляете процессом:
Вы сами спрашиваете у парсера: «Дай мне следующее событие!»
Аналогия:
SAX — это как телевидение: события «льются» на вас, вы должны реагировать.
StAX — это как сервис, где вы сами нажимаете «следующее видео», когда готовы.
Ключевые классы StAX
Чтобы работать со StAX, вам понадобятся два главных класса из пакета javax.xml.stream:
- XMLInputFactory — фабрика для создания парсеров.
- XMLStreamReader — сам потоковый парсер, который читает XML «по кусочкам».
Пример базового кода:
import javax.xml.stream.*;
import java.io.FileInputStream;
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("data.xml"));
while (reader.hasNext()) {
int event = reader.next();
// обработка события
}
reader.close();
2. Принцип работы StAX: pull-модель
В StAX вы сами управляете чтением XML:
- Открываете поток (например, файл).
- Создаёте XMLStreamReader.
- В цикле вызываете reader.next(), чтобы получить следующее событие.
- Проверяете тип события (START_ELEMENT, END_ELEMENT, CHARACTERS, и т.д.).
- Когда дошли до нужного места — обрабатываете данные.
- Закрываете парсер.
Схема работы:
В чём удобство?
- Вы сами решаете, когда читать следующий элемент.
- Можно «остановиться» в нужном месте, обработать только часть файла.
- Не нужно писать кучу обработчиков, как в SAX.
3. Типы событий в StAX
Когда вы вызываете reader.next(), парсер возвращает тип события — целое число (константа из интерфейса XMLStreamConstants). Вот основные типы событий:
- START_ELEMENT — начало XML-элемента (<tag>).
- END_ELEMENT — конец XML-элемента (</tag>).
- CHARACTERS — текстовое содержимое между тегами.
- END_DOCUMENT — конец документа.
Пример обработки событий:
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamConstants.START_ELEMENT:
String name = reader.getLocalName();
System.out.println("Начало элемента: " + name);
break;
case XMLStreamConstants.CHARACTERS:
String text = reader.getText().trim();
if (!text.isEmpty()) {
System.out.println("Текст: " + text);
}
break;
case XMLStreamConstants.END_ELEMENT:
System.out.println("Конец элемента: " + reader.getLocalName());
break;
}
}
4. Полезные нюансы
Когда использовать StAX?
StAX — идеальный выбор, если:
- XML-файл очень большой (гигабайты), и вы не хотите загружать его целиком в память.
- Нужно обработать только часть документа (например, найти определённый элемент и остановиться).
- Требуется простой и понятный код: StAX проще, чем SAX, и не требует писать кучу обработчиков.
Примеры задач:
- Импорт большого XML-файла с данными (например, выгрузка из 1С, банковские выписки, каталоги товаров).
- Поиск и обработка только нужных элементов (например, только <transaction> из миллиона записей).
- Преобразование XML «на лету» (например, фильтрация, агрегация).
Сравнение DOM, SAX и StAX
| Подход | Память | Простота | Гибкость | Когда использовать |
|---|---|---|---|---|
| DOM | Высокая (всё в памяти) | Очень прост | Можно изменять дерево | Маленькие/средние файлы, когда нужно редактировать XML |
| SAX | Минимальная | Сложно (обработчики событий) | Только чтение, нельзя вернуться назад | Очень большие файлы, простая обработка |
| StAX | Минимальная | Средне (pull-модель) | Можно читать по частям, удобно останавливать | Большие файлы, когда нужна гибкость и простота |
StAX — золотая середина:
— Не тратит память, как DOM.
— Не требует сложных обработчиков, как SAX.
— Позволяет управлять процессом парсинга.
5. Пример: чтение большого XML-файла с помощью StAX
Допустим, у нас есть файл "books.xml":
<library>
<book>
<title>Java для начинающих</title>
<author>Иван Иванов</author>
</book>
<book>
<title>Продвинутый Java</title>
<author>Пётр Петров</author>
</book>
<!-- ... много книг ... -->
</library>
Задача: вывести все названия книг.
Код на StAX:
import javax.xml.stream.*;
import java.io.*;
public class StaxDemo {
public static void main(String[] args) throws Exception {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("books.xml"));
while (reader.hasNext()) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT && "title".equals(reader.getLocalName())) {
reader.next(); // переходим к CHARACTERS
System.out.println("Книга: " + reader.getText());
}
}
reader.close();
}
}
Плюсы:
- Не загружаем весь файл в память.
- Можно обработать хоть миллион книг — программа не «упадёт».
6. Типичные ошибки при работе со StAX
Ошибка №1: забыли закрыть парсер или поток. Всегда закрывайте XMLStreamReader и поток (InputStream), чтобы не было утечек ресурсов.
Ошибка №2: не проверяете тип события. Не все события — это начало или конец элемента. Проверяйте тип события, иначе можно получить пустые строки или пропустить нужные данные.
Ошибка №3: не учитываете вложенность элементов. Если структура XML сложная (например, книги внутри разделов), следите за текущим уровнем вложенности, чтобы не перепутать элементы.
Ошибка №4: используете DOM для больших файлов. Если файл большой — не используйте DOM, иначе получите OutOfMemoryError. Для больших файлов — только StAX или SAX.
Ошибка №5: не обрабатываете исключения. Работа с файлами и XML может выбрасывать исключения (XMLStreamException, IOException). Обрабатывайте их или пробрасывайте выше.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ