DocumentBuilder.parse: примеры (JAVA)

Документация по DocumentBuilder.parse в Java
Раздел: Обработка XML, DOM
DocumentBuilder.parse(File f): Document

Описание DocumentBuilder.parse()

Метод DocumentBuilder.parse() из пакета javax.xml.parsers предназначен для преобразования XML-источника в объектную модель DOM (org.w3c.dom.Document). Часто применяется при необходимости программного чтения, анализа и модификации XML-документа в памяти.

Возвращаемое значение: объект org.w3c.dom.Document - корневое представление дерева XML после успешного разбора.

Перегрузки и возможные варианты аргументов:

  • Document parse(File f) - разбирает XML из файла.
  • Document parse(InputStream is) - принимает поток байтов; кодировка определяется декларацией XML или внешним механизмом.
  • Document parse(InputStream is, String systemId) - как выше, с указанием базового URI для разрешения относительных ссылок.
  • Document parse(String uri) - принимает строку-URL или путь, использует URI-ресурс.
  • Document parse(InputSource is) - гибкий вариант: InputSource может включать Reader, InputStream, systemId и encoding.

Взаимодействие с настройками парсера происходит через DocumentBuilderFactory и DocumentBuilder. Важные параметры, влияющие на поведение parse():

  • setNamespaceAware(boolean) - управление поддержкой пространств имен (xmlns).
  • setValidating(boolean) - валидация по DTD (если true, может требоваться DTD в документе).
  • setIgnoringElementContentWhitespace(boolean) - игнорирование пустого текста при наличии DTD/валидации.
  • Через DocumentBuilder можно установить EntityResolver для перехвата внешних сущностей и ErrorHandler для обработки ошибок при разборе.
  • Безопасность: рекомендуется явно задавать флаги/фичи, защищающие от XXE, например factory.setFeature("http://xml.org/sax/features/external-general-entities", false) и XMLConstants.FEATURE_SECURE_PROCESSING.

Исключения, которые может бросать parse():

  • org.xml.sax.SAXException - при нарушении формата или других ошибках парсинга.
  • IOException - при проблемах ввода-вывода (файл/сеть).
  • IllegalArgumentException - при null-аргументах в некоторых перегрузках.

Примечание: DocumentBuilder и DocumentBuilderFactory создаются через статические фабричные методы JAXP. В реальных проектах часто комбинируется настройка фабрики с последующей установкой обработчиков и фич для безопасного и предсказуемого разбора.

Короткие примеры использования

Пример 1 - разбор файла и вывод имени корневого элемента

import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.File;

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("example.xml"));
System.out.println(doc.getDocumentElement().getNodeName());
Результат:
exampleRoot

Пример 2 - разбор из InputStream с указанием systemId

try (InputStream is = new FileInputStream("example.xml")) {
    DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
    DocumentBuilder b = f.newDocumentBuilder();
    Document d = b.parse(is, new File("example.xml").toURI().toString());
    System.out.println(d.getDocumentElement().getTagName());
}
Результат:
exampleRoot

Пример 3 - использование InputSource с Reader и кодировкой

Reader r = new InputStreamReader(new FileInputStream("utf8.xml"), "UTF-8");
InputSource src = new InputSource(r);
src.setEncoding("UTF-8");
Document doc = builder.parse(src);
System.out.println(doc.getDocumentElement().getNodeName());
Результат:
utfRoot

Пример 4 - разбор по URI (HTTP)

Document doc = builder.parse("https://example.com/data.xml");
System.out.println(doc.getDocumentElement().getNodeName());
Результат:
remoteRoot (если доступен и корректен)

Похожие Java-решения и особенности

Вместо DOM-парсинга через DocumentBuilder нередко используются другие подходы:

  • SAXParser - потоковый (event-driven) парсер, экономит память при обработке больших файлов, не строит дерево в памяти. Предпочтителен для одноразовой последовательной обработки.
  • StAX (XMLStreamReader/ XMLStreamWriter) - pull-парсинг, дает контроль чтения событий и пригоден, когда требуется частичный доступ к документу или более простая логика, чем у SAX.
  • JDOM, DOM4J, XOM - альтернативные DOM-реализации с более удобным API и расширенными возможностями; хороши для удобной работы с XML, но требуют дополнительных зависимостей.
  • XPath (javax.xml.xpath) - применяется совместно с DOM для выборок узлов; для сложных выборок предпочтительнее, чем ручный обход дерева.

Выбор зависит от задач: DocumentBuilder удобен для модификации и навигации через стандартный DOM API; SAX/StAX - для производительности и низкого потребления памяти; внешние библиотеки - для удобного API и дополнительных функций.

Аналоги в других языках и отличия

Краткие эквиваленты parse()-функции в разных языках с примерами и результатами.

PHP - DOMDocument::load()

$doc = new DOMDocument();
$doc->load('example.xml');
echo $doc->documentElement->nodeName;
Результат:
exampleRoot

JavaScript (в браузере) - DOMParser

const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, 'application/xml');
console.log(doc.documentElement.nodeName);
Результат в консоли:
exampleRoot

Node.js - xml2js (модуль, конвертирует в JS-объект)

const fs = require('fs');
const xml2js = require('xml2js');
const xml = fs.readFileSync('example.xml', 'utf8');
xml2js.parseString(xml, (err, result) => console.log(result));
Результат:
JavaScript-объект, представляющий структуру XML

Python - xml.etree.ElementTree.parse()

import xml.etree.ElementTree as ET
tree = ET.parse('example.xml')
root = tree.getroot()
print(root.tag)
Результат:
exampleRoot

Python (lxml) - etree.parse()

from lxml import etree
doc = etree.parse('example.xml')
print(doc.getroot().tag)
Результат:
exampleRoot

C# - XmlDocument.Load()

var doc = new System.Xml.XmlDocument();
doc.Load("example.xml");
Console.WriteLine(doc.DocumentElement.Name);
Результат:
exampleRoot

Go - encoding/xml Unmarshal/Decoder

type Item struct {
    XMLName xml.Name `xml:"root"`
}
var it Item
decoder := xml.NewDecoder(file)
decoder.Decode(&it)
fmt.Println(it.XMLName.Local)
Результат:
root

Kotlin - использует Java API (DocumentBuilder) или kotlinx.serialization для других форматов. Отличие: прямой доступ к JVM-библиотекам.

Lua - lxp (LuaExpat) или другие парсеры; API event-driven и менее интегрирован в стандартную библиотеку.

Отличия от Java: в большинстве языков есть как DOM-подобные парсеры, так и потоковые. Java предоставляет богатую стандартную инфраструктуру JAXP, в то время как другие языки полагаются на стандартные или внешние библиотеки с различиями в управлении сущностями, поддержке пространств имен и поведении по умолчанию в отношении безопасности (XXE).

Типичные ошибки при использовании

Частые проблемы и примеры:

1) ParserConfigurationException при создании DocumentBuilder

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://xml.org/sax/features/external-general-entities", true);
DocumentBuilder builder = factory.newDocumentBuilder();
Возможный результат:
javax.xml.parsers.ParserConfigurationException: Feature not recognized

Пояснение: некоторые реализации не поддерживают выставленную фичу, либо запрещено в окружении.

2) SAXParseException при некорректном XML

DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("broken.xml"));
Возможный результат:
org.xml.sax.SAXParseException: The element type "tag" must be terminated by the matching end-tag

3) IOException при проблемах с доступом к ресурсу

Document doc = builder.parse("file:/nonexistent.xml");
Возможный результат:
java.io.FileNotFoundException: /nonexistent.xml (No such file or directory)

4) Проблемы с кодировкой при использовании InputStream без указания encoding

InputStream is = new FileInputStream("win1251.xml");
Document doc = builder.parse(is);
Возможный результат:
Некорректные символы в тексте при несоответствии кодировок

5) Уязвимость XXE (внешние сущности) при разборе ненадежного XML без отключения внешних сущностей

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File("untrusted.xml"));
Результат:
Возможная утечка данных через внешний ресурс, если в XML используется DOCTYPE и внешние сущности

Рекомендация: при разборе внешних данных отключать обработку внешних сущностей и включать FEATURE_SECURE_PROCESSING.

Изменения и примечания по версиям

API DocumentBuilder.parse() как таковой стабильна с момента стандартизации JAXP и не претерпевала значительных изменений в сигнатуре. Важные изменения и уточнения относятся к окружению и безопасности:

  • Модульность Java (JDK 9+) не изменила поведение parse(), но классы теперь находятся в модуле java.xml, что влияет на модульные переходы и доступность в модульных приложениях.
  • Добавлены и стандартизированы фичи безопасности (например, XMLConstants.FEATURE_SECURE_PROCESSING) и рекомендации по отключению внешних сущностей. Современные реализации и окружения могут по умолчанию ограничивать загрузку внешних DTD или сущностей.
  • Реализации поставщиков (Xerces, встроенный JDK парсер) обновлялись отдельно, что могло менять поддержку некоторых фич и поведение при обработке крайних случаев XML.

Вывод: явная настройка фабрики и builder-а рекомендуется для предсказуемого поведения в новых версиях JVM.

Расширенные и нестандартные примеры

1) Отключение XXE с кастомным EntityResolver

Пример java
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
f.setFeature("http://xml.org/sax/features/external-general-entities", false);
f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilder b = f.newDocumentBuilder();
// При желании можно установить EntityResolver, который отвечает пустым вводом
b.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader("")));
Document doc = b.parse(new File("untrusted.xml"));
System.out.println(doc.getDocumentElement().getNodeName());
Результат:
При наличии запрещенного DOCTYPE будет исключение или игнорирование внешних сущностей в зависимости от конфигурации

2) Использование ErrorHandler для агрегирования ошибок без прерывания выполнения

Пример java
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
List errors = new ArrayList<>();
builder.setErrorHandler(new org.xml.sax.ErrorHandler() {
    public void warning(org.xml.sax.SAXParseException e) { errors.add("WARN: " + e.getMessage()); }
    public void error(org.xml.sax.SAXParseException e) { errors.add("ERROR: " + e.getMessage()); }
    public void fatalError(org.xml.sax.SAXParseException e) throws org.xml.sax.SAXException { errors.add("FATAL: " + e.getMessage()); throw e; }
});
try {
    Document doc = builder.parse(new File("maybe-invalid.xml"));
} catch (Exception ex) {
    // обработка
}
errors.forEach(System.out::println);
Результат:
WARN: ...
ERROR: ... (в соответствии с содержимым)

3) Модификация DOM и запись результата в файл

Пример java
Document doc = builder.parse(new File("in.xml"));
Element root = doc.getDocumentElement();
Element newEl = doc.createElement("added");
newEl.setTextContent("value");
root.appendChild(newEl);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource src = new DOMSource(doc);
StreamResult res = new StreamResult(new File("out.xml"));
t.transform(src, res);
System.out.println("Saved to out.xml");
Результат:
Saved to out.xml
Файл out.xml содержит исходную структуру с добавленным элементом

4) Частичный разбор со совмещением StAX и DOM (экономия памяти)

Пример java
XMLInputFactory xf = XMLInputFactory.newInstance();
XMLStreamReader xr = xf.createXMLStreamReader(new FileInputStream("big.xml"));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
while (xr.hasNext()) {
    if (xr.next() == XMLStreamConstants.START_ELEMENT && "item".equals(xr.getLocalName())) {
        // создать поддерево для одного 
        XMLEventReader er = xf.createFilteredReader(xf.createXMLEventReader(new FileInputStream("big.xml")), ev -> true);
        // Здесь можно собрать событие для одного фрагмента и преобразовать в DOM при помощи трансформации
        break; // схематично
    }
}
Результат:
Позволяет обрабатывать поэлементно большие файлы, не загружая весь документ в память

5) Поиск узлов с XPath после parse()

Пример java
Document doc = builder.parse(new File("books.xml"));
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xpath.evaluate("/catalog/book[price>35]/title", doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) System.out.println(nodes.item(i).getTextContent());
Результат:
Список названий книг, цена которых больше 35

6) Кастомный EntityResolver для локального разрешения DTD

Пример java
builder.setEntityResolver((publicId, systemId) -> {
    if (systemId != null && systemId.endsWith("example.dtd")) {
        return new InputSource(new StringReader(""));
    }
    return null; // дальше по умолчанию
});
Document d = builder.parse(new File("with-doctype.xml"));
Результат:
DTD подставлен из кода, внешние обращения не выполнялись

Эти примеры демонстрируют способы безопасного и эффективного применения DocumentBuilder.parse() в различных сценариях: защита, обработка ошибок, интеграция с другими API и экономия памяти.

джава DocumentBuilder.parse function comments

En
DocumentBuilder.parse Парсит XML-документ из файла