Чтение XML в Java с помощью DOM

Java DOM XML Для работы с XML в Java есть достаточно большой набор инструментов, начиная от встроенных возможностей (я имею в виду возможности, которые предоставляет Core Java без использования дополнительных lib’ов) и заканчивая большим набором разнообразного стороннего кода, оформленного в виде отдельных библиотек. К примеру есть очень интересная библиотека, которую я совсем недавно использовал для того, чтобы сериализовывать класс в XML и наоборот, создавать из XML представления класса конкретный экземпляр. Библиотека называется XStream, если кому интересно, то вот она http://xstream.codehaus.org Пока что остановимся на средствах, которые входят в стандартную JDK, а именно на DOM — Document Object Model.

Так что же такое DOM? Судя из названия это есть объектная модель документа. XML документ представляет собой набор тегов — узлов. Каждый узел может иметь неограниченное количество дочерних узлов. Каждый дочерний тоже может содержать много-много потомков или не содержать их вовсе. Таким образом получается некое дерево. Так вот DOM представляет собой всё это дерево в виде специальных объектов Node. Каждый Node соответствует своему XML-тегу. Каждый Node содержит полную информацию о том, что это за тег, какие он имеет атрибуты, какие дочерние узлы содержит внутри себя и так далее. На самой вершине этой иерархии находится Document.

Для того, чтобы получить объект Document для нашего XML-файла необходимо выполнить следующий код.

DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setValidating(false);
DocumentBuilder builder = f.newDocumentBuilder();
Document doc = builder.parse(new File("test.xml"));

У нас имеется корневой узел документа Document. Теперь при помощи DOM методов можно произвести разбор документа, добраться до нужного узла иерархии и прочитать его свойства. Можно получить список дочерних узлов при помощи метода getChildNodes.

NodeList methodNodes = node.getChildNodes();

Вот так можно пробежаться по всем дочерним узлам текущего узла:

NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
     Node node = children.item(i);
}

С помощью getAttributes получается NamedNodeMap, который содержит атрибуты узла. Вот так можно получить значение атрибута «name»:

NamedNodeMap attributes = node.getAttributes();
Node nameAttrib = attributes.getNamedItem("name");
String name = nameAttrib.getNodeValue();

Используя метод getNodeType можно узнать тип узла вот так:

if (node.getNodeType() == Node.ELEMENT_NODE) {
    ...
}

Посмотрим теперь на тестовый пример. Тестовое приложение читает тестовый xml файл, содержимое которого представлено ниже, извлекает данные из него и отображает пользователю.

 
<?xml version="1.0" encoding="UTF-8"?>
<application>
	<class name = "MainClass">
		<method name = "main"/>
	</class>	
	<class name = "Window">
		<method name = "open"/>
		<method name = "close"/>
		<method name = "show"/>
		<method name = "hide"/>
	</class>		
	<class name = "DataBase">
		<method name = "connect"/>
		<method name = "disconnect"/>
		<method name = "getData"/>
	</class>		
</application>

А это код тестового приложения, которое должно выглядеть так, как показано на рисунке ниже.
Чтение XML в Java с помощью DOM

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class TestFrame extends JFrame {

	private static final String SPACE = "   ";

	/**
	 * Создаем интерфейс приложения.
	 */
	public static void createGUI() {
		final JFrame frame = new JFrame("Test frame");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		final Font font = new Font("Verdana", Font.PLAIN, 13);

		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());

		final JTextArea textArea = new JTextArea(15, 10);
		panel.add(new JScrollPane(textArea), BorderLayout.CENTER);
		textArea.setFont(font);

		JButton parseButton = new JButton("Parse XML");
		parseButton.setFont(font);
		panel.add(parseButton, BorderLayout.SOUTH);

		parseButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					Document doc = getDocument();
					showDocument(doc, textArea);
				} catch (Exception ex) {
					JOptionPane.showMessageDialog(frame, ex.getMessage());
				}
			}
		});

		frame.getContentPane().add(panel);

		frame.setPreferredSize(new Dimension(280, 220));
		frame.pack();
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
	}

	/**
	 * Возвращает объект Document, который является объектным представлением
	 * XML документа.
	 */
	private static Document getDocument() throws Exception {
		try {
			DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
			f.setValidating(false);
			DocumentBuilder builder = f.newDocumentBuilder();
			return builder.parse(new File("test.xml"));
		} catch (Exception exception) {
			String message = "XML parsing error!";
			throw new Exception(message);
		}
	}

	private static void showDocument(Document doc, JTextArea textArea) {
		StringBuffer content = new StringBuffer();
		Node node = doc.getChildNodes().item(0);
		ApplicationNode appNode = new ApplicationNode(node);

		content.append("Application \n");

		List<ClassNode> classes = appNode.getClasses();

		for (int i = 0; i < classes.size(); i++) {
			ClassNode classNode = classes.get(i);
			content.append(SPACE + "Class: " + classNode.getName() + " \n");

			List<MethodNode> methods = classNode.getMethods();

			for (int j = 0; j < methods.size(); j++) {
				MethodNode methodNode = methods.get(j);
				content.append(SPACE + SPACE + "Method: "
						+ methodNode.getName() + " \n");
			}
		}

		textArea.setText(content.toString());
	}

	public static void main(String[] args) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				JFrame.setDefaultLookAndFeelDecorated(true);
				createGUI();
			}
		});
	}

	/**
	 * Объектное представление приложения.
	 */
	public static class ApplicationNode {

		Node node;

		public ApplicationNode(Node node) {
			this.node = node;
		}

		public List<ClassNode> getClasses() {
			ArrayList<ClassNode> classes = new ArrayList<ClassNode>();

			/**
			 * Получаем список дочерних узлов для данного узла XML, который
			 * соответствует приложению application. Здесь будут располагаться
			 * все узлы Node, каждый из которых является объектным
			 * представлением тега class для текущего тега application.
			 */
			NodeList classNodes = node.getChildNodes();

			for (int i = 0; i < classNodes.getLength(); i++) {
				Node node = classNodes.item(i);

				if (node.getNodeType() == Node.ELEMENT_NODE) {

					/**
					 * Создаем на основе Node узла своё объектное
					 * представление класса.
					 */
					ClassNode classNode = new ClassNode(node);
					classes.add(classNode);
				}
			}

			return classes;
		}

	}

	/**
	 * Объектное представление класса.
	 */
	public static class ClassNode {

		Node node;

		/**
		 * Создаем новый экземпляр объекта на основе Node узла.
		 */
		public ClassNode(Node node) {
			this.node = node;
		}

		/**
		 * Возвращает список методов класса.
		 */
		public List<MethodNode> getMethods() {
			ArrayList<MethodNode> methods = new ArrayList<MethodNode>();

			/**
			 * Получаем список дочерних узлов для данного узла XML, 
			 * который соответствует классу class. Здесь будут располагаться 
			 * все узлы Node, каждый из которых является объектным 
			 * представлением тега method для текущего тега class.
			 */
			NodeList methodNodes = node.getChildNodes();

			for (int i = 0; i < methodNodes.getLength(); i++) {
				node = methodNodes.item(i);

				if (node.getNodeType() == Node.ELEMENT_NODE) {

					/**
					 * Создаем на основе Node узла своё объектное представление
					 * метода.
					 */
					MethodNode methodNode = new MethodNode(node);
					methods.add(methodNode);
				}
			}

			return methods;
		}

		/**
		 * Возвращае имя класса.
		 */
		public String getName() {

			/**
			 * Получаем атрибуты узла метода.
			 */
			NamedNodeMap attributes = node.getAttributes();

			/**
			 * Получаем узел аттрибута.
			 */
			Node nameAttrib = attributes.getNamedItem("name");

			/**
			 * Возвращаем значение атрибута.
			 */
			return nameAttrib.getNodeValue();
		}
	}

	/**
	 * Объектное представление сущности метод класса.
	 */
	public static class MethodNode {

		Node node;

		/**
		 * Создаем новый экземпляр объекта на основе Node узла.
		 */
		public MethodNode(Node node) {
			this.node = node;
		}

		/**
		 * Возвращает имя метода.
		 */
		public String getName() {

			/**
			 * Получаем атрибуты узла метода.
			 */
			NamedNodeMap attributes = node.getAttributes();

			/**
			 * Получаем узел аттрибута.
			 */
			Node nameAttrib = attributes.getNamedItem("name");

			/**
			 * Возвращаем значение атрибута.
			 */
			return nameAttrib.getNodeValue();
		}

	}

}

14 Responses to Чтение XML в Java с помощью DOM

  1. chevalry says:

    Небольшое добавление. Как раз разбирался именно с этим примером, но только у меня тестовый XML-файл содержит информацию не в атрибутах, а внутри элементов. Когда начал у себе переделывать класс MethodNode, то по ошибке пытался прочитать содержимое элемента с помощью
    node.getNodeValue()
    и получал в результате null. Сперва не понял, в чем тема — потом разобрался. Вместо это следует использовать:
    node.getTextContent()
    Мелочь, конечно, но может — кому пригодиться…

  2. Kostos says:

    Спасибо за статью, очень нужная, одна у вас в коде есть ошибка:

    скорее всего не
    NodeList methodNodes = node.getChildNodes();

    а
    NodeList methodNodes = doc.getChildNodes();

    ибо переменная node нигде не объявлена.

  3. Satana says:

    Очень хорошая статья.
    Было бы не плохо почитать еще и про запись данных в XML.

  4. Nekkyi says:

    Здравствуйте. У меня такая проблема. Имею исходный файл

    qqqq

    Считываю его при помощи DOM анализатора и записываю обратно. В итоге получаю

    qqqq

    Соответственно вопрос. Как сделать так чтобы не преобразовывалась в ?

  5. WcN says:

    Вот у всех примеры с линейным файлом и с единичной глубиной вложенности… 😦

  6. knight says:

    return builder.parse(newFile(«res/xml/as.xml»));

    парни вот тут бьет ошибку, помоги как правильно загружать файл? или может какие-то права в манифесте прописывать надо? я никак не пойму что нужно сделать

  7. Mumish says:

    вместо открытого файла возвращает null

  8. Mumish says:

    виноват — показалось

  9. Over Driven says:

    Все идеально, кроме JFrame. Уровень статьи, не для повышения квалификации специалистов, а для новичка JFrame здесь на себя отвлекает внимание. Нужно было просто в консоль вывести.

Оставьте комментарий