DOM 객체를 수정, 추가, 삭제하는 것은 모두 메모리상에서 이루어진다.
이렇게 메모리상에서 변경된 내용을 영구 보존하기 위해서는 다시 파일 형태의 XML 문서로 저장해야 한다.
XSLT 변환기를 사용하여 파일로 다시 저장하는 방법을 알아보자~
노드를 생성하기 위한 메서드(Document 객체의 팩토리 메서드)
메소드 | 설명 |
Element createElement(String tagName) | Element 객체를 생성 |
Attr createAttribute(String name) | Att 객체를 생성 |
Text createTextNode(data) | Text 객체를 생성 |
Comment createComment(data) | Comment 객체를 생성 |
CDATASection createCDATASection(data) |
CDATASection 객체를 생성 |
노드의 추가, 삭제를 하기 위한 메서드(Node 인터페이스의 메서드)
메소드 | 설명 |
Node appendChild(Node newChild) | newChild를 자식 노드의 끝에 추가 |
Node removeChild(Node oldChild) | oldChild를 자식 노드에서 삭제 |
Node insertBefore(Node newChild, Node oldChild) | oldChild 앞에 newChild를 삽입 |
Node replaceChild(Node newChild, Node oldChild) | oldChild를 newChild로 교체 |
void setNodeValue(String nodeValue) | 노드의 값(텍스트 노드의 경우는 텍스트, 주석 노드의 경우는 주석 내용)을 설정 |
void setTextContent(String textContent) | 이 노드의 텍스트를 설정 |
1. 문자열을 XML 파일로 생성 및 조작하기
1) XSLT 변환기는 javax.xml.transform.Transformer 추상 클래스를 상속한 객체를 말한다.
Transformer를 생성하기 위해서는 먼저 javax.xml.transform.TransformerFactory 객체를 생성한 뒤 이 객체를 통해서 Transformer 객체를 생성한다.
2) 변환기가 DOM객체 트리를 XML문서 파일로 만들 때 XML 선언과 문서 유형 선언 부분에 기술될 내용을 다음과 같이 설정한다.
* XSLT 확장 가능한 스타일시트 언어 변환의 요소 참조
- omit-xml-declaration은 출력에 XML 선언을 포함할지 여부를 나타내며, 설정할 수 있는 값은 " yes" 또는 " no"입니다.
더 많은 내용은 아래 링크 참고하기!
https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/output
<xsl:output> - XSLT: Extensible Stylesheet Language Transformations | MDN
The <xsl:output> element controls the characteristics of the output document. To function correctly in Netscape, this element, with the method attribute, must be used. As of 7.0, method="text" works as expected.
developer.mozilla.org
3) 저장할 대상인 원본 XML 문서를 Source 객체로 생성한 뒤 여기서는 XML 문서가 DOM 객체트리로 존재하기 때문에 javax.xml.transform.dom.DOMSource 객체를 생성해야 한다.
DOMSource 생성자의 인자로 루트 노드인 Document 객체를 넘겨준다.
다른 객체들은 모두 루트노드의 자식 객체들이므로 자동적으로 같이 넘어간다고 생각하면 된다!
4) 이제 XML 문서를 저장할 곳의 위치 정보를 가지고 있는 Result 객체를 생성해야 한다.
여기에서는 파일로 저장되기 때문에 javax.xml.transform.stream.StreamResult 객체를 생성해야한다.
5) 마지막으로 변환기의 transform() 메소드를 실행하여 파일로 저장한다.
[전체적인 코드 보기]
import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import java.io.*;
public class SaveDOMToFile {
public static void main(String[] args) throws Exception {
// DOM 파서 생성
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
// XML 문서 파싱하기
Document document = builder.parse("src/ch9/bml.xml");
// 루트 엘리먼트 참조 얻기
Element eRoot = document.getDocumentElement();
// 여기서부터 해당 내용 코드들
// 변환기 생성
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
// 출력 포맷 설정
transformer.setOutputProperty(OutputKeys.ENCODING,"utf-8");
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"bml.dtd");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// DOMSource 객체 생성
DOMSource source = new DOMSource(document);
// StreamResult 객체 생성
StreamResult result = new StreamResult(new File("c:\\bml2.xml"));
// 파일로 저장하기
transformer.transform(source,result);
System.out.println("완료");
}
}
XML 파일을 생성하는 것은 예제를 통해 살펴보자
결과물
코드
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class DOMParser {
public static void main(String[] args) throws ParserConfigurationException, IOException, TransformerException{
// XML 문서 파싱
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
// 새로운 XML 생성! //
// 새로운 Document 객체 생성
Document document = documentBuilder.newDocument();
// root 생성
Element root = document.createElement("class");
// root 속성 설정
root.setAttribute("name", "어떻게 xml parser를 사용할까?");
// 자식 노드 생성
Element people = document.createElement("people");
people.setAttribute("name", "p1");
// 텍스트 설정
people.setTextContent("유재석입니다.");
Element people2 = document.createElement("people");
people2.setAttribute("name", "p2");
// 텍스트 설정
people2.setTextContent("강호동입니다.");
Element people3 = document.createElement("people");
people3.setAttribute("name", "p3");
// 텍스트 설정
people3.setTextContent("야리니입니다.");
// 자식 요소 추가
document.appendChild(root);
root.appendChild(people);
root.appendChild(people2);
root.appendChild(people3);
// XML 문자열로 변환하기! //
ByteArrayOutputStream out = new ByteArrayOutputStream();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(out);
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
// 출력 시 문자코드: UTF-8
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
// 들여 쓰기 있음
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(source, result);
System.out.println(new String(out.toByteArray(), StandardCharsets.UTF_8));
}
}
다른 결과물로도 코드를 확인해보자
결과
코드
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// book 엘리먼트
Document doc = docBuilder.newDocument();
doc.setXmlStandalone(true); //standalone="no" 를 없애준다.
Element book = doc.createElement("book");
doc.appendChild(book);
// code 엘리먼트
Element code = doc.createElement("code");
book.appendChild(code);
// 속성값 정의 (id:1)
code.setAttribute("id", "1");
//code.setAttribute("type", "novel");
// name 엘리먼트
Element name = doc.createElement("name");
name.appendChild(doc.createTextNode("사람은 무엇으로 사는가?"));
code.appendChild(name);
// writer 엘리먼트
Element writer = doc.createElement("writer");
writer.appendChild(doc.createTextNode("톨스토이"));
code.appendChild(writer);
// price 엘리먼트
Element price = doc.createElement("price");
price.appendChild(doc.createTextNode("100"));
code.appendChild(price);
code = doc.createElement("code");
book.appendChild(code);
// 속성값 정의 (id:2)
code.setAttribute("id", "2");
code.setAttribute("type", "novel");
// name 엘리먼트
name = doc.createElement("name");
name.appendChild(doc.createTextNode("홍길동 전"));
code.appendChild(name);
// writer 엘리먼트
writer = doc.createElement("writer");
writer.appendChild(doc.createTextNode("허균"));
code.appendChild(writer);
// price 엘리먼트
price = doc.createElement("price");
price.appendChild(doc.createTextNode("300"));
code.appendChild(price);
// XML 파일로 쓰기
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); //정렬 스페이스4칸
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //들여쓰기
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes"); //doc.setXmlStandalone(true); 했을때 붙어서 출력되는부분 개행
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new FileOutputStream(new File("D://tmp/book.xml")));
transformer.transform(source, result);
2. XPath를 사용하여 DOM 트리의 임의의 노드를 검색하기
XPath를 사용하면 DOM 트리의 임의의 노드를 쉽게 검색할 수 있다. XPath는 XML 문서를 검색하기 위한 쿼리 언어이다!
예를 들어, XML 문서 내에서 name 속성 값이 "s1"인 student 요소를 검색하는 XPath는 다음과 같다.
student[@name='s1']
DOM 트리를 XPath를 사용해 검색하는 예제를 살펴보자
import java.io.IOException;
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.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class DOMParser {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException{
// XML 문서 파싱
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
Document document = documentBuilder.parse("sample.xml");
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
// XPath를 컴파일
XPathExpression expr = xpath.compile("//student");
XPathExpression expr2 = xpath.compile("//student[@name='s2']");
// XPath에서 XML 문서를 검색
Object result = expr.evaluate(document, XPathConstants.NODESET);
Object result2 = expr2.evaluate(document, XPathConstants.NODESET);
NodeList nodes = (NodeList)result;
for(int i = 0; i < nodes.getLength(); i++){
Element element = (Element)nodes.item(i);
System.out.println("att1: " + element.getAttribute("name"));
}
nodes = (NodeList)result2;
for(int i = 0; i < nodes.getLength(); i++){
Element element = (Element)nodes.item(i);
System.out.println("att2: " + element.getAttribute("name"));
}
}
}
결과
att1: s1
att1: s2
att1: s3
att2: s2
expr은 student 요소를 모두 찾는 식이고, expr2는 name 속성 값이 's2'인 student 요소를 찾는 식이다.
evaluate() 메서드로 XML 문서에 대해 검색하며, 반환값은 NodeList형 이다.
XPath는 선택하는 요소 이름을 /로 구분하여 지정한다. 속성을 지정하는 경우는 "@속성명"으로 지정한다.
아래는 자주 사용하는 XPath이다.
예시 | 설명 |
student | 현재 노드 아래의 student 요소 |
./student | 현재 노드 아래의 student 요소 |
/student | root 노드 아래의 student 요소 |
//student | 트리 내의 모든 student 요소 |
student/* | student 요소 아래의 모든 노드 |
student/@name | student 요소의 name 속성 |
student[@name='s1'] | name 속성이 's1'인 student 요소 |
student[starts-with(@name,'s1')] | name 속성이 's1'로 시작하는 student 요소 |
//student[text()='abc'] | 텍스트가 'abc'인 student 요소 |
참고
https://huskdoll.tistory.com/869
https://byul91oh.tistory.com/327
'TIL > Java' 카테고리의 다른 글
[Java] com.fasterxml.jackson.databind.ObjectMapper(JSON <-> Java Object) (0) | 2022.11.04 |
---|---|
[Java] StringUtils 클래스 (0) | 2022.10.04 |
[SIST] Java_days29 (0) | 2022.03.31 |
[SIST] Java_days28 (0) | 2022.03.29 |
[SIST] Java_days27 (0) | 2022.03.28 |