В этой статье мы рассмотрим пример работы с XPath в Java, а именно научимся находить нужную нам информацию с помощью XPath выражений и делать выборку из XML документа по различным условиям.
Кратко сведения про XPath
XPath предоставляет специальный синтаксис для поиска и выборки данных в XML документе. Используя XPath выражения, мы можем произвести выборку по условию, найти узлы или точное значение из любой части XML-документа.
XPath является частью платформы Java SE и находится в пакете javax.xml.xpath
, поэтому никаких дополнительных зависимостей подключать не нужно — все работает прямо из коробки.
Для создания выражения для выборки по условию используется класс XPathExpression
, который создается с помощью фабричных методов XPathFactory.newInstance()
и вызова xpathFactory.newXPath()
. Результат выборки должен быть представлен одним из 5 возможных типов:
XPathConstants.STRING
XPathConstants.NUMBER
XPathConstants.BOOLEAN
XPathConstants.NODE
XPathConstants.NODESET
Подробнее ниже в примере.
Пример работы с XPath в Java
Перед нами стоит задача получить информацию из XML файла разработчиков по следующим критериям:
- Узнать имена разработчиков, возраст которых меньше заданного в условии.
- Получить имена всех мидлов.
- Получить имя по известному id.
У нас есть XML документ с таким содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Developers> <Developer id="1"> <name>Andrew</name> <age>25</age> <position>Middle</position> <language>Java</language> </Developer> <Developer id="2"> <name>Dima</name> <age>21</age> <position>Junior</position> <language>JS</language> </Developer> <Developer id="3"> <name>Alex</name> <age>23</age> <position>Junior</position> <language>Java</language> </Developer> <Developer id="4"> <name>Irena</name> <age>27</age> <position>Middle</position> <language>JS</language> </Developer> </Developers> |
Как искать с помощью XPath?
Рассмотрим одно из выражений XPathExpression
, которое мы будем использовать в нашей программе:
Получить имена всех мидлов:
1 2 3 |
XPathExpression xPathExpression = xpath.compile( "/Developers/Developer[position='Middle']/name/text()" ); |
В данном случае на вход методу compile()
передается строка с условиями поиска (выражение), по результатам выполнения который создается новый объект XPathExpression
.
В самом выражении мы указываем, что хотим искать в узлах Developer, которые находятся в корневом Developers. В каждом из этих узлов Developer мы хотим зайти в тег position и посмотреть, не является ли его значение равно ‘Middle’ — если true, то зайти в тег name текущего узла Developer и получить значение этого тега с помощью метода text().
Аналогично работаем с другими условиями, только вместо условия [position=’Middle’] задаем соответствующие критерии:
Возраст меньше заданного в age
:
1 |
/Developers/Developer[age<" + age + "]/name/text() |
Имя по известному id
:
1 |
/Developers/Developer[@id='" + id + "']/name/text() |
Найти id можно, например, по имени:
1 |
/Developers/developer[name='Irena']/@id |
Обратите внимание, для атрибута id используется символ @
.
Теперь напишем класс, который реализует описанные выше задачи:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
package ua.com.prologistic.xpath; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class XPathTest { public static void main(String[] args) { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); // включаем поддержку пространства имен XML builderFactory.setNamespaceAware(true); DocumentBuilder builder; Document doc = null; try { builder = builderFactory.newDocumentBuilder(); doc = builder.parse("F:/developers.xml"); // Создаем объект XPathFactory XPathFactory xpathFactory = XPathFactory.newInstance(); // Получаем экзмепляр XPath для создания // XPathExpression выражений XPath xpath = xpathFactory.newXPath(); String devName = getDeveloperNameById(doc, xpath, 1); System.out.println("Имя разработчика с id = 1: " + devName); List<String> names = getDevelopersWithAge(doc, xpath, 23); System.out.println("Разработчики, младше 23 лет: " + names.toString()); List<String> middleDevelopers = getMiddleDevelopers(doc, xpath); System.out.println("Работают на позиции Middle Developer: " + middleDevelopers.toString()); } catch (ParserConfigurationException | SAXException | IOException e) { e.printStackTrace(); } } private static List<String> getMiddleDevelopers(Document doc, XPath xpath) { List<String> list = new ArrayList<>(); try { //создаем объект XPathExpression XPathExpression xPathExpression = xpath.compile( "/Developers/Developer[position='Middle']/name/text()" ); // получаем список всех тегов, которые отвечают условию NodeList nodes = (NodeList) xPathExpression.evaluate(doc, XPathConstants.NODESET); // проходим по списку и получаем значение с помощью getNodeValue() for (int i = 0; i < nodes.getLength(); i++) list.add(nodes.item(i).getNodeValue()); } catch (XPathExpressionException e) { e.printStackTrace(); } return list; } private static List<String> getDevelopersWithAge(Document doc, XPath xpath, int age) { List<String> list = new ArrayList<>(); try { // получаем список всех узлов, которые отвечают условию XPathExpression xPathExpression = xpath.compile( "/Developers/Developer[age<" + age + "]/name/text()" ); NodeList nodeList = (NodeList) xPathExpression.evaluate(doc, XPathConstants.NODESET); for (int i = 0; i < nodeList.getLength(); i++) list.add(nodeList.item(i).getNodeValue()); } catch (XPathExpressionException e) { e.printStackTrace(); } return list; } private static String getDeveloperNameById(Document doc, XPath xpath, int id) { String devName = null; try { XPathExpression xPathExpression = xpath.compile( "/Developers/Developer[@id='" + id + "']/name/text()" ); devName = (String) xPathExpression.evaluate(doc, XPathConstants.STRING); } catch (XPathExpressionException e) { e.printStackTrace(); } return devName; } } |
Теперь запустим нашу программу и посмотрим вывод на консоль:
1 2 3 |
Имя разработчика с id = 1: Andrew Разработчики, младше 23 лет: [Dima] Работают на позиции Middle Developer: [Irena] |
Как видите, все результаты выборки совпадают с данными в исходном XML файле.
Читайте другие статьи по обработке XML в Java, а также подписывайтесь на новые материалы по Java и Android!
А как вывести на печать значение атрибута id, относительно этого примера?
Найти id можно, например, по имени:
/Developers/developer[name=’Irena’]/@id