Java에서 XML 속성 수정

1. 소개

XML로 작업 할 때 일반적인 활동 중 하나는 해당 속성으로 작업하는 것입니다. 이 자습서에서는 Java를 사용하여 XML 속성을 수정하는 방법을 살펴 봅니다.

2. 종속성

테스트를 실행하려면 Maven 프로젝트에 JUnit 및 xmlunit-assertj 종속성을 추가해야합니다 .

 org.junit.jupiter junit-jupiter 5.5.0 test 
 org.xmlunit xmlunit-assertj 2.6.3 test 

3. JAXP 사용

XML 문서부터 시작하겠습니다.

  [email protected] [email protected] 

이를 처리하기 위해 버전 1.4부터 Java와 함께 번들로 제공되는 JAXP (Java API for XML Processing)를 사용합니다 .

customer 속성을 수정 하고 값을 false로 변경해 보겠습니다 .

첫째, 우리는 구축하는 데 필요한 문서 는 XML 파일에서 개체를 그렇게, 우리가 사용합니다 의 DocumentBuilderFactory를 :

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); factory.setFeature("//apache.org/xml/features/disallow-doctype-decl", true); Document input = factory .newDocumentBuilder() .parse(resourcePath);

DocumentBuilderFactory 클래스에 대한 외부 엔티티 처리 (XXE)비활성화 하기 위해 XMLConstants.FEATURE_SECURE_PROCESSING//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); }

또는 for 루프 대신 IntStream을 사용할 수 있습니다 .

IntStream .range(0, nodes.getLength()) .mapToObj(i -> (Element) nodes.item(i)) .forEach(value -> value.setAttribute(attribute, newValue));

이제 Transformer 객체를 사용 하여 변경 사항을 적용 해 보겠습니다 .

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이 표시됩니다 .

  [email protected] [email protected] 

또한 단위 테스트에서 확인해야하는 경우 XMLUnitassertThat 메서드를 사용할 수 있습니다 .

assertThat(output.toString()).hasXPath("//*[contains(@customer, 'false')]");

4. dom4j 사용

dom4j는 XPath와 통합되고 DOM, SAX, JAXP 및 Java 컬렉션을 완벽하게 지원하는 XML 처리를위한 오픈 소스 프레임 워크입니다.

4.1. Maven 종속성

프로젝트에서 dom4j를 사용하려면 pom.xml 에 dom4j 및 jaxen 종속성을 추가해야합니다 .

 org.dom4j dom4j 2.1.1   jaxen jaxen 1.2.0 

XML 라이브러리 지원 문서에서 dom4j에 대해 자세히 알아볼 수 있습니다.

4.2. org.dom4j.Element.addAttribute 사용

dom4j는 XML 요소에 대한 추상화로 Element 인터페이스를 제공합니다 . addAttribute 메서드를 사용하여 고객 속성 을 업데이트 할 것입니다.

이것이 어떻게 작동하는지 봅시다.

먼저 XML 파일에서 Document 객체를 만들어야합니다 . 이번에SAXReader를 사용합니다 .

SAXReader xmlReader = new SAXReader(); Document input = xmlReader.read(resourcePath); xmlReader.setFeature("//apache.org/xml/features/disallow-doctype-decl", true); xmlReader.setFeature("//xml.org/sax/features/external-general-entities", false); xmlReader.setFeature("//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); List nodes = 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)는 DOM이 필요하지만 너무 장황한 곳에서 유창한 XML 문서 생성 및 조작을 허용 하는 org.w3c.dom 패키지 의 래퍼입니다 . jOOX는 기본 문서 만 래핑하며 대안이 아닌 DOM을 향상시키는 데 사용할 수 있습니다.

5.1. Maven 종속성

프로젝트에서 jOOX를 사용하려면 pom.xml 에 종속성을 추가해야합니다 .

Java 9+와 함께 사용하려면 다음을 사용할 수 있습니다.

 org.jooq joox 1.6.2 

또는 Java 6 이상에서는 다음이 제공됩니다.

 org.jooq joox-java-6 1.6.2 

Maven Central 저장소에서 최신 버전의 jooxjoox-java-6 을 찾을 수 있습니다 .

5.2. Using org.w3c.dom.Element.setAttribute

The jOOX API itself is inspired by jQuery, as we can see in the examples below. Let's see how to use it.

First, we need to load the Document:

DocumentBuilder builder = JOOX.builder(); Document input = builder.parse(resourcePath);

Now, we need to select it:

Match $ = $(input);

In order to select the customer Element, we can use the find method or an XPath expression. In both cases, we'll get a list of the elements that match it.

Let's see the find method in action:

$.find("to") .get() .stream() .forEach(e -> e.setAttribute(attribute, newValue));

To get the result as a String, we simply need to call the toString() method:

$.toString();

6. Benchmark

In order to compare the performance of these libraries, we used a JMH benchmark.

Let's see the results:

| 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. 결론

이 빠른 자습서에서는 JAXP, dom4j 및 jOOX를 사용하여 XML 속성을 수정하는 방법을 소개했습니다. 또한 JMH 벤치 마크를 사용하여 이러한 라이브러리의 성능을 측정했습니다.

평소처럼 여기에 표시된 모든 코드 샘플은 GitHub에서 사용할 수 있습니다.