Изменение атрибута XML на Java
1. Введение
Одним из распространенных действий при работе с XML является работа с его атрибутами. В этом учебнике мы изумим, как изменить атрибут XML с помощью Java.
2. Зависимости
Для того, чтобы запустить наши тесты, мы должны добавить JUnit и xmlunit-assertj зависимостей от нашей Мавен проект:
org.junit.jupiter junit-jupiter 5.5.0 test
org.xmlunit xmlunit-assertj 2.6.3 test
3. Использование JAXP
Начнем с документа XML:
Для того, чтобы обработать его, мы использовать Java API для обработки XML (JAXP) , который был в комплекте с Java с версии 1.4.
Давайте изменим обслуживание атрибут и изменить его значение на ложные .
Во-первых, мы должны построить Документ объект из файла XML, и для этого мы будем использовать ДокументОстроительФактория :
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); Document input = factory .newDocumentBuilder() .parse(resourcePath);
Обратите внимание, что для того, отключить внешняя обработка сущности (XXE) для ДокументОстроительФактория класс, мы настраиваем XMLConstants.FEATURE_SECURE_PROCESSING и http://apache.org/xml/features/disallow-doctype-decl особенности . Это хорошая практика, чтобы настроить его, когда мы разобрать ненадежные файлы XML.
После инициализации нашего входные объект, нам нужно найти узел с атрибутом, который мы хотели бы изменить. Давайте использовать XPath выражение выбрать его:
XPath xpath = XPathFactory .newInstance() .newXPath(); String expr = String.format("//*[contains(@%s, '%s')]", attribute, oldValue); NodeList nodes = (NodeList) xpath.evaluate(expr, input, XPathConstants.NODESET);
В этом случае XPath оценить метод возвращает нам список узлов с совещенными узлами.
Давайте итерировать по списку, чтобы изменить значение:
for (int i = 0; i < nodes.getLength(); i++) { Element value = (Element) nodes.item(i); value.setAttribute(attribute, newValue); }
Или, вместо для цикл, мы можем использовать IntStream :
IntStream .range(0, nodes.getLength()) .mapToObj(i -> (Element) nodes.item(i)) .forEach(value -> value.setAttribute(attribute, newValue));
Теперь, давайте использовать Трансформатор объект для применения изменений:
TransformerFactory factory = TransformerFactory.newInstance(); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer xformer = factory.newTransformer(); xformer.setOutputProperty(OutputKeys.INDENT, "yes"); Writer output = new StringWriter(); xformer.transform(new DOMSource(input), new StreamResult(output));
Если мы напечатаем выходной объект содержание, мы получим в результате XML с обслуживание атрибут изменен:
Кроме того, мы можем использовать утверждать, что метод XMLUnit если нам нужно проверить это в единице теста:
assertThat(output.toString()).hasXPath("//*[contains(@customer, 'false')]");
4. Использование dom4j
dom4j представляет собой платформу с открытым исходным кодом для обработки XML, которая интегрирована с XPath и полностью поддерживает DOM, SAX, JAXP и Java Коллекции.
4.1. Зависимость от Maven
Нам нужно добавить dom4j и джаксен зависимостей от нашей пом.xml использовать dom4j в нашем проекте:
org.dom4j dom4j 2.1.1 jaxen jaxen 1.2.0
Мы можем узнать больше о dom4j в нашей статье поддержки библиотек XML .
4.2. Использование org.dom4j.Element.addAttribute
dom4j предлагает Элемент интерфейс как абстракция для элемента XML. Мы будем использовать addAttribute метод обновления наших обслуживание атрибут.
Давайте посмотрим, как это работает.
Во-первых, мы должны построить Документ объект из файла XML – на этот раз мы будем использовать SAXЧитатель :
SAXReader xmlReader = new SAXReader(); Document input = xmlReader.read(resourcePath); xmlReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
Мы устанавливаем дополнительные функции для предотвращения XXE.
Как и JAXP, мы можем использовать выражение XPath для выбора узлов:
String expr = String.format("//*[contains(@%s, '%s')]", attribute, oldValue); XPath xpath = DocumentHelper.createXPath(expr); Listnodes = xpath.selectNodes(input);
Теперь мы можем итерировать и обновлять атрибут:
for (int i = 0; i < nodes.size(); i++) { Element element = (Element) nodes.get(i); element.addAttribute(attribute, newValue); }
Обратите внимание, что с помощью этого метода, если атрибут уже существует для данного имени, он будет заменен. В противном случае, он будет добавлен.
Для печати результатов мы можем повторно использовать код из предыдущего раздела JAXP.
5. Использование jOOX
jOOX (jOOX Object-Oriented XML) — обертка для org.w3c.dom пакет, который позволяет свободно XML создание документов и манипуляции, где DOM требуется, но слишком многословно. jOOX только обертывает базовый документ и может быть использован для повышения DOM, а не в качестве альтернативы.
5.1. Зависимость от Maven
Мы должны добавить зависимость к нашей пом.xml использовать jOOX в нашем проекте.
Для использования с Java 9 “, мы можем использовать:
org.jooq joox 1.6.2
Или с Java 6 “, у нас есть:
org.jooq joox-java-6 1.6.2
Мы можем найти последние версии джоокс и joox-java-6 в Центральном хранилище Maven.
5.2. Использование org.w3c.dom.Element.setAttribute
JOOX API сам вдохновлен j-Кери , как мы можем видеть в примерах ниже. Давайте посмотрим, как его использовать.
Во-первых, мы должны загрузить Документ :
DocumentBuilder builder = JOOX.builder(); Document input = builder.parse(resourcePath);
Теперь нам нужно выбрать его:
Match $ = $(input);
Для того, чтобы выбрать элемент клиента, мы можем использовать найти метод или выражение XPath. В обоих случаях мы получим список элементов, которые соответствуют ему.
Посмотрим на найти метод в действии:
$.find("to") .get() .stream() .forEach(e -> e.setAttribute(attribute, newValue));
Чтобы получить результат в Струнные , мы просто должны позвонить toString () метод:
$.toString();
6. Контрольный показатель
Для сравнения производительности этих библиотек мы использовали бенчмарк JMH.
Давайте посмотрим результаты:
| Benchmark Mode Cnt Score Error Units | |--------------------------------------------------------------------| | AttributeBenchMark.dom4jBenchmark avgt 5 0.150 ± 0.003 ms/op | | AttributeBenchMark.jaxpBenchmark avgt 5 0.166 ± 0.003 ms/op | | AttributeBenchMark.jooxBenchmark avgt 5 0.230 ± 0.033 ms/op |
Как мы видим, для этого случая использования и нашей реализации, dom4j и JAXP имеют лучшие оценки, чем jOOX.
7. Заключение
В этом быстром учебнике мы представили, как модифицировать атрибуты XML с помощью JAXP, dom4j и jOOX. Кроме того, мы измерили производительность этих библиотек с помощью бенчмарка JMH.
Как обычно, все образцы кода, показанные здесь, доступны на GitHub .