Java를 사용하는 XPath 소개

1. 개요

이 기사에서는 표준 Java JDK에서 지원하는 XPath의 기본 사항에 대해 살펴 보겠습니다 .

간단한 XML 문서를 사용하여 처리하고 문서에서 필요한 정보를 추출하는 방법을 살펴 보겠습니다.

XPath는 W3C에서 권장하는 표준 구문이며 XML 문서를 탐색하기위한 일련의 표현식입니다. 여기에서 전체 XPath 참조를 찾을 수 있습니다.

2. 간단한 XPath 파서

import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; public class DefaultParser { private File file; public DefaultParser(File file) { this.file = file; } } 

이제 DefaultParser 에서 찾을 수있는 요소를 자세히 살펴 보겠습니다 .

FileInputStream fileIS = new FileInputStream(this.getFile()); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); Document xmlDocument = builder.parse(fileIS); XPath xPath = XPathFactory.newInstance().newXPath(); String expression = "/Tutorials/Tutorial"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);

그것을 분해 해보자 :

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();

이 객체를 사용하여 xml 문서에서 DOM 객체 트리를 생성합니다.

DocumentBuilder builder = builderFactory.newDocumentBuilder();

이 클래스의 인스턴스가 있으면 InputStream , File , URLSAX 와 같은 다양한 입력 소스에서 XML 문서를 구문 분석 할 수 있습니다 .

Document xmlDocument = builder.parse(fileIS);

문서 ( org.w3c.dom.Document는 ), 문서 트리의 루트이며, 전체 XML 문서를 나타내는 데이터에 대한 우리의 첫 번째 액세스를 제공합니다 :

XPath xPath = XPathFactory.newInstance().newXPath();

XPath 객체에서 표현식에 액세스하고 문서에서이를 실행하여 필요한 것을 추출합니다.

xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);

문자열로 전달 된 XPath 표현식을 컴파일하고 예를 들어 NODESET , NODE 또는 String 을받을 것으로 예상되는 데이터의 종류를 정의 할 수 있습니다.

3. 시작하자

이제 우리가 사용할 기본 구성 요소를 살펴 보았으므로 테스트 목적으로 간단한 XML을 사용하는 코드로 시작하겠습니다.

   Guava Introduction to Guava 04/04/2016 GuavaAuthor   XML Introduction to XPath 04/05/2016 XMLAuthor  

3.1. 기본 요소 목록 검색

첫 번째 방법은 XML에서 노드 목록을 검색하기 위해 XPath 표현식을 사용하는 간단한 방법입니다.

FileInputStream fileIS = new FileInputStream(this.getFile()); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); Document xmlDocument = builder.parse(fileIS); XPath xPath = XPathFactory.newInstance().newXPath(); String expression = "/Tutorials/Tutorial"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); 

위의 표현식을 사용하거나 " // Tutorial " 표현식을 사용하여 루트 노드에 포함 된 자습서 목록을 검색 할 수 있지만이 목록은 모든 항목을 검색합니다. 문서의 어디에 있든 상관없이 현재 노드의 문서 노드는 현재 노드에서 시작하는 트리의 모든 수준을 의미합니다.

NodeList를 그 지정하여 반환 노드 집합을 반환 형식으로 컴파일 명령에이 매개 변수로 인덱스를 전달하여 액세스 할 수있는 노드의 정렬 된 모음입니다.

3.2. ID로 특정 노드 검색

필터링만으로 주어진 ID를 기반으로 요소를 찾을 수 있습니다.

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); Document xmlDocument = builder.parse(this.getFile()); XPath xPath = XPathFactory.newInstance().newXPath(); String expression = "/Tutorials/Tutorial[@tutId=" + "'" + id + "'" + "]"; node = (Node) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODE); 

이러한 종류의 표현식을 사용하면 올바른 구문을 사용하여 찾아야하는 요소를 필터링 할 수 있습니다. 이러한 종류의 식을 조건 자라고하며 문서에서 특정 데이터를 쉽게 찾을 수 있습니다. 예를 들면 다음과 같습니다.

/ 튜토리얼 / 튜토리얼 [1]

/ 튜토리얼 / 튜토리얼 [first ()]

/ 튜토리얼 / 튜토리얼 [position () <4]

여기서 술어의 전체 참조를 찾을 수 있습니다.

3.3. 특정 태그 이름으로 노드 검색

이제 축을 도입하여 더 나아가서 XPath 표현식에서 사용하여 이것이 어떻게 작동하는지 살펴 보겠습니다.

Document xmlDocument = builder.parse(this.getFile()); this.clean(xmlDocument); XPath xPath = XPathFactory.newInstance().newXPath(); String expression = "//Tutorial[descendant::title[text()=" + "'" + name + "'" + "]]"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); 

위에 사용 된 표현으로 우리는 자손이있는 요소 "name"변수에 매개 변수로 전달 된 텍스트와 함께.

이 기사에 제공된 샘플 xml에 따라 "Guava"또는 "XML"텍스트를 포함하고 전체를 검색합니다. 모든 데이터가있는 요소.

Axes는 XML 문서를 탐색하는 매우 유연한 방법을 제공하며 공식 사이트에서 전체 문서를 찾을 수 있습니다.

3.4. 식에서 데이터 조작

XPath를 사용하면 필요한 경우 표현식에서도 데이터를 조작 할 수 있습니다.

XPath xPath = XPathFactory.newInstance().newXPath(); String expression = "//Tutorial[number(translate(date, '/', '')) > " + date + "]"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); 

이 표현식에서 "ddmmyyyy"와 같은 날짜로 간단한 문자열을 메서드에 전달하지만 XML은이 데이터를 " dd / mm / yyyy " 형식으로 저장 하므로 결과를 일치시키기 위해 문자열을 조작하여 변환합니다. 문서에서 사용하는 올바른 데이터 형식으로 변경하고 XPath에서 제공하는 함수 중 하나를 사용하여 수행합니다.

3.5. 네임 스페이스가 정의 된 문서에서 요소 검색

If our xml document has a namespace defined as it is in the example_namespace.xml used here, the rules to retrieve the data we need are going to change since our xml starts like this:

Now when we use an expression similar to “//Tutorial”, we are not going to get any result. That XPath expression is going to return all elements that aren't under any namespace, and in our new example_namespace.xml, all elements are defined in the namespace /full_archive.

Lets see how to handle namespaces.

First of all we need to set the namespace context so XPath will be able to know where are we looking for our data:

xPath.setNamespaceContext(new NamespaceContext() { @Override public Iterator getPrefixes(String arg0) { return null; } @Override public String getPrefix(String arg0) { return null; } @Override public String getNamespaceURI(String arg0) { if ("bdn".equals(arg0)) { return "/full_archive"; } return null; } }); 

In the method above, we are defining “bdn” as the name for our namespace “/full_archive“, and from now on, we need to add “bdn” to the XPath expressions used to locate elements:

String expression = "/bdn:Tutorials/bdn:Tutorial"; nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET); 

Using the expression above we are able to retrieve all elements under “bdn” namespace.

3.6. Avoiding Empty Text Nodes Troubles

As you could notice, in the code at the 3.3 section of this article a new function is called just right after parsing our XML to a Document object, this .clean( xmlDocument );

Sometimes when we iterate through elements, childnodes and so on, if our document has empty text nodes we can find an unexpected behavior in the results we want to get.

We called node .getFirstChild() when we are iterating over all elements looking for the information, but instead of what we are looking for we just have “#Text” as an empty node.

To fix the problem we can navigate through our document and remove those empty nodes, like this:

NodeList childs = node.getChildNodes(); for (int n = childs.getLength() - 1; n >= 0; n--) { Node child = childs.item(n); short nodeType = child.getNodeType(); if (nodeType == Node.ELEMENT_NODE) { clean(child); } else if (nodeType == Node.TEXT_NODE) { String trimmedNodeVal = child.getNodeValue().trim(); if (trimmedNodeVal.length() == 0){ node.removeChild(child); } else { child.setNodeValue(trimmedNodeVal); } } else if (nodeType == Node.COMMENT_NODE) { node.removeChild(child); } }

By doing this we can check each type of node we find and remove those ones we don't need.

4. Conclusions

Here we just introduced the default XPath provided support, but there are many popular libraries as JDOM, Saxon, XQuery, JAXP, Jaxen or even Jackson now. There are libraries for specific HTML parsing too like JSoup.

It's not limited to java, XPath expressions can be used by XSLT language to navigate XML documents.

As you can see, there is a wide range of possibilities on how to handle these kind of files.

XML / HTML 문서 구문 분석, 읽기 및 처리를위한 기본적으로 훌륭한 표준 지원이 있습니다. 여기에서 전체 작동 샘플을 찾을 수 있습니다.