Последнее обновление 12.09.2023 — Василий Иванов
XML-файлы могут служить различным целям, включая хранение данных. До того, как JSON стал популярным, предпочтительным форматом для представления, хранения и транспортировки структурированных данных был XML.
Несмотря на то, что популярность XML в последние годы пошла на убыль, время от времени вы можете с ним столкнуться, поэтому важно научиться с ним работать. Узнайте, как использовать DOM API для чтения и записи XML-файлов с помощью Java.
Требования для обработки XML в Java
Java Standard Edition (SE) включает Java API для обработки XML (JAXP), который представляет собой общий термин, охватывающий большинство аспектов обработки XML. К ним относятся:
- DOM: объектная модель документа включает классы для работы с объектами XML, такими как элементы, узлы и атрибуты. DOM API загружает весь XML-документ в память для обработки, поэтому он не очень подходит для больших XML-файлов.
- SAX: Simple API for XML — это управляемый событиями API для чтения XML. Он генерирует события в ответ на содержимое XML, которое он находит при анализе файла. Затраты памяти у этого метода невелики, но работать с API сложнее, чем с DOM.
- StAX: API потоковой передачи для XML появился недавно. Он обеспечивает высокопроизводительную фильтрацию потоков, обработку и модификацию XML. Хотя он позволяет избежать загрузки всего XML-документа в память, он обеспечивает архитектуру по запросу, а не архитектуру, управляемую событиями, поэтому его проще кодировать, чем SAX API.
Для обработки XML в Java вам необходимо импортировать эти пакеты:
import javax.xml.parsers.*;
import javax.xml.transform.*;
import org.w3c.dom.*;
Подготовка образца XML-файла
Чтобы понять пример кода и лежащие в его основе концепции, используйте этот пример XML-файла от Microsoft. Вот отрывок:
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
...snipped...
Чтение XML-файла с помощью DOM API
Давайте рассмотрим основные шаги, необходимые для чтения XML-файла с помощью DOM API. Начните с создания экземпляра DocumentBuilder, который вы будете использовать для анализа XML-документа:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Теперь вы можете загрузить весь документ в память, начиная с корневого элемента XML. В нашем примере это элемент каталога.
// XML file to read
File file = "<path_to_file>";
Document document = builder.parse(file);
Element catalog = document.getDocumentElement();
Вот и все; теперь у вас есть доступ ко всему XML-документу, начиная с его корневого элемента — каталога.
Извлечение информации с помощью DOM API
Теперь, когда у вас есть корневой элемент XML, вы можете использовать DOM API для извлечения интересных фрагментов информации. Например, возьмите все дочерние элементы book корневого элемента и переберите их. Обратите внимание, что getChildNodes() возвращает всех дочерних элементов, включая текст, комментарии и т. д. Для вашей цели вам нужны только дочерние элементы, поэтому вы можете пропустить остальные:
NodeList books = catalog.getChildNodes();
for (int i = 0, ii = 0, n = books.getLength() ; i < n ; i++) {
Node child = books.item(i);
if ( child.getNodeType() != Node.ELEMENT_NODE )
continue;
Element book = (Element)child;
// work with the book Element here
}
Как найти конкретный дочерний элемент по родительскому элементу? Создайте статический метод, который возвращает первый соответствующий элемент, если он найден, или значение NULL. Процедура включает в себя получение списка дочерних узлов и циклическое перебор их, выбирая узлы элементов с указанным именем.
static private Node findFirstNamedElement(Node parent,String tagName)
{
NodeList children = parent.getChildNodes();
for (int i = 0, in = children.getLength() ; i < in ; i++) {
Node child = children.item(i);
if (child.getNodeType() != Node.ELEMENT_NODE)
continue;
if (child.getNodeName().equals(tagName))
return child;
}
return null;
}
Обратите внимание, что DOM API рассматривает текстовое содержимое внутри элемента как отдельный узел типа TEXT_NODE. Текстовое содержимое может состоять из нескольких соседних текстовых узлов, поэтому для получения текста элемента потребуется специальная обработка:
static private String getCharacterData(Node parent)
{
StringBuilder text = new StringBuilder();
if ( parent == null )
return text.toString();
NodeList children = parent.getChildNodes();
for (int k = 0, kn = children.getLength() ; k < kn ; k++) {
Node child = children.item(k);
if (child.getNodeType() != Node.TEXT_NODE)
break;
text.append(child.getNodeValue());
}
return text.toString();
}
Вооружившись этими удобными функциями, взгляните на этот код, чтобы получить некоторую информацию из примера XML. Он показывает подробную информацию о каждой книге, доступной в каталоге:
NodeList books = catalog.getChildNodes();
for (int i = 0, ii = 0, n = books.getLength() ; i < n ; i++) {
Node child = books.item(i);
if (child.getNodeType() != Node.ELEMENT_NODE)
continue;
Element book = (Element)child;
ii++;
String id = book.getAttribute("id");
String author = getCharacterData(findFirstNamedElement(child, "author"));
String title = getCharacterData(findFirstNamedElement(child, "title"));
String genre = getCharacterData(findFirstNamedElement(child, "genre"));
String price = getCharacterData(findFirstNamedElement(child, "price"));
String pubdate = getCharacterData(findFirstNamedElement(child, "pubdate"));
String descr = getCharacterData(findFirstNamedElement(child, "description"));
System.out.printf("%3d. book id = %s\n" +
" author: %s\n" +
" title: %s\n" +
" genre: %s\n" +
" price: %s\n" +
" pubdate: %s\n" +
" descr: %s\n",
ii, id, author, title, genre, price, pubdate, descr);
}
Вот пошаговое объяснение кода:
- Код перебирает дочерние узлы каталога, корневой элемент.
- Для каждого дочернего узла, представляющего книгу, проверяется, является ли тип узла ELEMENT_NODE. Если нет, он переходит к следующей итерации.
- Если дочерний узел является ELEMENT_NODE, (Element)child преобразует его в объект Element.
- Затем код извлекает из элемента книги различные атрибуты и символьные данные, включая «идентификатор», «автор», «название», «жанр», «цену», «дату публикации» и «описание». Он печатает эти данные с помощью метода System.out.printf.
Вот как выглядит результат:
Написание XML-вывода с использованием Transform API
Java предоставляет API преобразования XML для преобразования данных XML. Мы используем этот API с преобразованием идентичности для генерации вывода. В качестве примера добавим новый элемент книги в образец каталога, представленный выше.
Вы можете получить сведения о книге (автор, название и т. д.) из внешнего источника, например файла свойств или базы данных. В качестве примера вы можете использовать следующий файл свойств:
id=bk113
author=Jane Austen
title=Pride and Prejudice
genre=Romance
price=6.99
publish_date=2010-04-01
description="It is a truth universally acknowledged, that a single man in possession of a good fortune must be in want of a wife." So begins Pride and Prejudice, Jane Austen's witty comedy of manners-one of the most popular novels of all time-that features splendidly civilized sparring between the proud Mr. Darcy and the prejudiced Elizabeth Bennet as they play out their spirited courtship in a series of eighteenth-century drawing-room intrigues.
Первым шагом является анализ существующего XML-файла с использованием метода, представленного выше:
File file = ...; // XML file to read
Document document = builder.parse(file);
Element catalog = document.getDocumentElement();
Теперь вы загружаете данные из файла свойств, используя класс Properties, предусмотренный в Java. Код довольно прост:
String propsFile = "<path_to_file>";
Properties props = new Properties();
try (FileReader in = new FileReader(propsFile)) {
props.load(in);
}
После загрузки свойств вы можете получить значения, которые хотите добавить, из файла свойств:
String id = props.getProperty("id");
String author = props.getProperty("author");
String title = props.getProperty("title");
String genre = props.getProperty("genre");
String price = props.getProperty("price");
String publish_date = props.getProperty("publish_date");
String descr = props.getProperty("description");
Теперь создайте пустой элемент книги.
Element book = document.createElement("book");
book.setAttribute("id", id);
Добавление дочерних элементов в книгу тривиально. Для удобства вы можете собрать имена необходимых элементов в список и добавлять значения в цикле.
List<String> elnames =Arrays.asList("author", "title", "genre", "price",
"publish_date", "description");
for (String elname : elnames) {
Element el = document.createElement(elname);
Text text = document.createTextNode(props.getProperty(elname));
el.appendChild(text);
book.appendChild(el);
}
catalog.appendChild(book);
В элемент каталога теперь добавлен новый элемент книги. Теперь остается только записать обновленный XML.
Чтобы написать XML, вам понадобится экземпляр Transformer, который вы можете создать следующим образом:
TransformerFactory tfact = TransformerFactory.newInstance();
Transformer tform = tfact.newTransformer();
tform.setOutputProperty(OutputKeys.INDENT, "yes");
tform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
Вы можете использовать setOutputProperty() для запроса отступа вывода.
Последний шаг — применить преобразование. Результат появляется в выходном потоке System.out.
tform.transform(new DOMSource(document), new StreamResult(System.out));
Чтобы записать вывод непосредственно в файл, используйте следующее:
tform.transform(new DOMSource(document), new StreamResult(new File("output.xml")));
Это все шаги, необходимые для чтения и записи XML-файлов на Java.
Теперь вы знаете, как читать и записывать XML-файлы с помощью Java.
Анализ XML и манипулирование им с помощью Java — ценный навык, который вы часто будете использовать в реальных программах. API-интерфейсы DOM и Transform особенно полезны.
Понимание DOM, в частности, жизненно важно, если вы планируете писать клиентский код для веб-приложений или сайтов. Интерфейс DOM универсален, поэтому вы можете работать с ним, используя аналогичный код на таких разных языках, как Java и JavaScript.