Разбор DOM с Xerces

Работа с XML-файлами в Java с использованием анализа DOM

1. обзор

В этом руководстве мы обсудим, как анализировать DOM с помощьюApache Xerces - зрелой и устоявшейся библиотеки для синтаксического анализа / управления XML.

Есть несколько вариантов синтаксического анализа XML-документа; в этой статье мы сосредоточимся на синтаксическом анализе DOM. Парсер DOM загружает документ и создает в памяти все иерархическое дерево.

Обзор поддержки библиотек XML в Java можно найти в наших предыдущихarticle.

2. Наш документ

Начнем с XML-документа, который мы будем использовать в нашем примере:



    
        Guava
        Introduction to Guava
        04/04/2016
        GuavaAuthor
    
...

Обратите внимание, что в нашем документе есть корневой узел под названием «учебники» с 4 «учебными» дочерними узлами. Каждый из них имеет 2 атрибута: «tutId» и «тип». Также каждый «учебник» имеет 4 дочерних узла: «заголовок», «описание», «дата» и «автор».

Теперь мы можем продолжить анализ этого документа.

3. Загрузка XML-файла

Во-первых, мы должны отметить, чтоthe Apache Xerces library is packaged with the JDK, поэтому нам не нужна дополнительная настройка.

Давайте сразу перейдем к загрузке нашего XML-файла:

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(new File("src/test/resources/example_jdom.xml"));
doc.getDocumentElement().normalize();

В приведенном выше примере мы сначала получаем экземпляр классаDocumentBuilder, а затем используем методparse() в XML-документе, чтобы получить объектDocument, представляющий его.

Нам также необходимо использовать методnormalize(), чтобы гарантировать, что на иерархию документа не влияют лишние пробелы или новые строки внутри узлов.

4. Разбор DOM

Теперь давайте исследуем наш XML-файл.

Начнем с извлечения всех элементов с тегом «tutorial». Мы можем сделать это с помощью методаgetElementsByTagName(), который вернетNodeList:

@Test
public void whenGetElementByTag_thenSuccess() {
    NodeList nodeList = doc.getElementsByTagName("tutorial");
    Node first = nodeList.item(0);

    assertEquals(4, nodeList.getLength());
    assertEquals(Node.ELEMENT_NODE, first.getNodeType());
    assertEquals("tutorial", first.getNodeName());
}

Важно отметить, чтоNode is the primary datatype for the DOM components. Все элементы, атрибуты, текст считаются узлами.

Затем давайте посмотрим, как мы можем получить атрибуты первого элемента с помощьюgetAttributes():

@Test
public void whenGetFirstElementAttributes_thenSuccess() {
    Node first = doc.getElementsByTagName("tutorial").item(0);
    NamedNodeMap attrList = first.getAttributes();

    assertEquals(2, attrList.getLength());

    assertEquals("tutId", attrList.item(0).getNodeName());
    assertEquals("01", attrList.item(0).getNodeValue());

    assertEquals("type", attrList.item(1).getNodeName());
    assertEquals("java", attrList.item(1).getNodeValue());
}

Здесь мы получаем объектNamedNodeMap, а затем используем методitem(index) для получения каждого узла.

Для каждого узла мы можем использоватьgetNodeName() иgetNodeValue(), чтобы найти их атрибуты.

5. Узлы обхода

Затем давайте посмотрим, как обходить узлы DOM.

В следующем тесте мы пройдем по дочерним узлам первого элемента и распечатаем их содержимое:

@Test
public void whenTraverseChildNodes_thenSuccess() {
    Node first = doc.getElementsByTagName("tutorial").item(0);
    NodeList nodeList = first.getChildNodes();
    int n = nodeList.getLength();
    Node current;
    for (int i=0; i

Сначала мы получаемNodeList с помощью методаgetChildNodes(), затем перебираем его и печатаем имя узла и текстовое содержимое.

Вывод покажет содержимое первого элемента «учебник» в нашем документе:

title: Guava
description: Introduction to Guava
date: 04/04/2016
author: GuavaAuthor

6. Модификация DOM

Мы также можем внести изменения в DOM.

В качестве примера изменим значение атрибутаtype с «java» на «другое»:

@Test
public void whenModifyDocument_thenModified() {
    NodeList nodeList = doc.getElementsByTagName("tutorial");
    Element first = (Element) nodeList.item(0);

    assertEquals("java", first.getAttribute("type"));

    first.setAttribute("type", "other");
    assertEquals("other", first.getAttribute("type"));
}

Здесь для изменения значения атрибута достаточно вызвать методElement ’ssetAttribute().

7. Создание нового документа

Помимо изменения DOM, мы также можем создавать новые XML-документы с нуля.

Давайте сначала посмотрим на файл, который мы хотим создать:



    
        [email protected]
    

Наш XML содержит корневой узелusers с одним элементомuser, который также имеет дочерний узелemail.

Для этого сначала нужно вызвать методBuilder‘snewDocument(), который возвращает объектDocument.

Затем мы вызовем методcreateElement() нового объекта:

@Test
public void whenCreateNewDocument_thenCreated() throws Exception {
    Document newDoc = builder.newDocument();
    Element root = newDoc.createElement("users");
    newDoc.appendChild(root);

    Element first = newDoc.createElement("user");
    root.appendChild(first);
    first.setAttribute("id", "1");

    Element email = newDoc.createElement("email");
    email.appendChild(newDoc.createTextNode("[email protected]"));
    first.appendChild(email);

    assertEquals(1, newDoc.getChildNodes().getLength());
    assertEquals("users", newDoc.getChildNodes().item(0).getNodeName());
}

Чтобы добавить каждый элемент в DOM, мы также вызываем методappendChild().

8. Сохранение документа

После изменения нашего документа или создания его с нуля нам нужно будет сохранить его в файл.

Мы начнем с создания объектаDOMSource, а затем воспользуемся простымTransformer для сохранения документа в файл:

private void saveDomToFile(Document document,String fileName)
  throws Exception {

    DOMSource dom = new DOMSource(document);
    Transformer transformer = TransformerFactory.newInstance()
      .newTransformer();

    StreamResult result = new StreamResult(new File(fileName));
    transformer.transform(dom, result);
}

Точно так же мы можем напечатать наш документ в консоли:

private void printDom(Document document) throws Exception{
    DOMSource dom = new DOMSource(document);
    Transformer transformer = TransformerFactory.newInstance()
        .newTransformer();

    transformer.transform(dom, new StreamResult(System.out));
}

9. Заключение

В этой быстрой статье мы узнали, как использовать синтаксический анализатор Xerces DOM для создания, изменения и сохранения XML-документа.

Как всегда, доступен полный исходный код примеровover on GitHub.