Java EE 정리 21
27 Mar 2019
Reading time ~8 minutes
Java EE 정리 21 - XML 생성, DTD
JDOM Parser를 이용한 Attribute Parsing
- 노드에 속성(Attribute)를 Parsing할 수 있다.
<?xml ... >
<부모노드>
<자식노드 속성명="값" />
...
</부모노드>
// 노드 얻기
Element el = rootNode.getChilde("자식노드명");
// 속성 얻기
Attribute attr = el.getAttribute("속성명");
// 속성의 값 얻기
String attrVal = attr.getValue();
- 속성 Parsing 예
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<people>
<person>
<name lastName="김">정윤</name>
<address city="강남구" zipcode="12345">신사동</address>
</person>
<person>
<name lastName="김">희철</name>
<address city="관악구" zipcode="36454">신사동</address>
</person>
<person>
<name lastName="노">진경</name>
<address city="강서구" zipcode="76543">강화동</address>
</person>
<person>
<name lastName="김">민정</name>
<address city="관악구" zipcode="66542">청림동</address>
</person>
<person>
<name lastName="정">택성</name>
<address city="구로구" zipcode="76543">개봉동</address>
</person>
</people>
public class AttrVO {
private String firstName, lastName, city, zipcode, address;
// 기본,인자있는 생성자, getter, setter ..
...
public class AttrParsing {
public List<AttrVO> personDataParsing(String lastName) throws MalformedURLException, JDOMException, IOException {
List<AttrVO> list = new ArrayList<AttrVO>();
// 1. Builder(Parser) 생성
SAXBuilder sb = new SAXBuilder();
// 2. XML 읽기
Document doc = sb.build(new URL("http://localhost:8080/jsp_prj/xml0327/attr.xml"));
// 3. 최상위 부모노드 얻기
Element peopleNode = doc.getRootElement();
// 4. 처음 자식노드들 얻기
Iterator<Element> personNodes = peopleNode.getChildren().iterator();
Element personNode = null;
Element personSubNode = null;
Attribute lastNameAttr = null;
Attribute cityAttr = null;
Attribute zipcodeAttr = null;
String lastNameAttrVal = "";
AttrVO avo = null;
// 5. people 자식노드만큼 반복
while(personNodes.hasNext()) {
// person 노드 얻기
personNode = personNodes.next();
// person의 자식 노드들 얻기
Iterator<Element> personSubNodes = personNode.getChildren().iterator();
while(personSubNodes.hasNext()) {
personSubNode = personSubNodes.next(); // name, address
// 1. name 노드면
if ("name".equals(personSubNode.getName())) {
// lastName 속성값을 구하고
lastNameAttr = personSubNode.getAttribute("lastName");
lastNameAttrVal = lastNameAttr.getValue();
// 성이 같으면 VO 생성
if (lastName.equals(lastNameAttrVal)) {
avo = new AttrVO();
// 이름 set
avo.setLastName(lastNameAttrVal);
avo.setFirstName(personSubNode.getText());
}
}
// 2. 성이 같다면
if (lastName.equals(lastNameAttrVal)) {
// 주소 노드의 값 set
if ("address".equals(personSubNode.getName())) {
cityAttr = personSubNode.getAttribute("city");
zipcodeAttr = personSubNode.getAttribute("zipcode");
// 주소를 set
avo.setCity(cityAttr.getValue());
avo.setZipcode(zipcodeAttr.getValue());
avo.setAddress(personSubNode.getText());
list.add(avo);
}
}
}
}
return list;
}
}
<!-- attr_parsing.jsp -->
...
<script type="text/javascript">
$(function() {
$("#btn").click(function() {
$("[name='frm']").submit();
});
}); // ready
</script>
...
<div>
<form name="frm" action="attr_parsing.jsp" method="get">
<select id="lastName" name="lastName">
<option value="김">김씨</option>
<option value="이">이씨</option>
<option value="박">박씨</option>
<option value="정">정씨</option>
<option value="노">노씨</option>
<option value="최">최씨</option>
</select>
<input type="button" value="조회" id="btn" class="btn"/>
</form>
</div>
<c:if test="${ not empty param.lastName }">
<div>
<div>선택하신 "${ param.lastName }"으로 조회한 결과입니다.</div>
<div>
<%
String lastName = request.getParameter("lastName");
AttrParsing ap = new AttrParsing();
List<AttrVO> list = ap.personDataParsing(lastName);
pageContext.setAttribute("personList", list);
%>
<table border="1">
<tr>
<th width="100">이름</th>
<th width="400">주소</th>
</tr>
<c:if test="${ empty personList }">
<tr>
<td colspan="2" align="center">검색결과가 존재하지 않습니다.</td>
</tr>
</c:if>
<c:forEach var="data" items="${ personList }">
<tr>
<td><c:out value="${ data.lastName }"/><c:out value="${ data.firstName }"/></td>
<td>(${ data.zipcode }) ${ data.city } ${ data.address }</td>
</tr>
</c:forEach>
</table>
</div>
</div>
</c:if>
...
XML 생성 - Java로 만들기
- XML은 Java 또는 JDOM Parser로 만들 수 있다.
- XML을 만드는 작업을 Thread로 수행하면 지속적으로 XML을 업데이트 할 수 있음
- Java로 XML 만들기
- DB로부터 데이터 얻기
- 얻은 데이터로 XML형태의 String 생성
- 출력스트림으로 XML 출력
public class CreateXML {
public List<String> data() {
List<String> list = new ArrayList<String>();
list.add("월래 먹는 날");
list.add("화끈하게 먹는 날");
list.add("수도없이 먹는 날");
list.add("목이 터지게 먹는 날");
list.add("금새먹고 또 먹는 날");
list.add("토하면서 먹는 날");
list.add("일일이 찾아다니며 먹는 날");
return list;
}
public String createXML(List<String> weekMsg) {
StringBuilder xml = new StringBuilder();
xml.append("<?xml version='1.0' encoding='UTF-8'?>\n");
xml.append("<week>\n");
for(int i=0; i < weekMsg.size(); i++) {
xml.append("\t<msg>").append(weekMsg.get(i)).append("</msg>\n");
}
xml.append("</week>");
return xml.toString();
}
public void createXMLFile(String xml) throws IOException {
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("C:/.../msg.xml"),"UTF-8"));
bw.write(xml);
bw.flush();
} finally {
if (bw != null) { bw.close(); }
}
}
public static void main(String[] args) {
CreateXML c = new CreateXML();
try {
c.createXMLFile(c.createXML(c.data()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
XML 생성 - Parser로 만들기
- XML 문서 객체 생성
- 선언부가 생성됨
Document doc = new Document(); // <? xml ... ?>
- 최상위 부모 노드를 생성
- 한개만 생성
Element rootNode = new Element("부모노드");
- 자식노드 생성
- 여러개 생성가능
Element subNode1 = new Element("자식노드1"); // <자식노드1/>
Element subNode2 = new Element("자식노드2");
Element subNode3 = new Element("자식노드3");
- 자식노드에 들어갈 값 설정
subNode1.setText("값1"); // <자식노드1>값1</자식노드1>
subNode2.setText("값2");
subNode3.setText("값3");
- 속성을 가지는 경우
// 속성객체 생성
Attribute attr = new Attribute("속성명1", "속성값1");
// 속성객체를 노드객체에 추가
subNode1.setAttribute(attr); // <자식노드1 속성명1="속성값1">값1</자식노드1>
- 자식노드를 부모노드에 추가(반복)
rootNode.addContent(subNode1);
rootNode.addContent(subNode2);
rootNode.addContent(subNode3);
/*
<부모노드>
<자식노드1 속성명1="속성값1">값1<자식노드1>
<자식노드2>값2</자식노드2>
<자식노드3>값3</자식노드3>
</부모노드>
*/
- 자식노드를 가진 부모노드를 문서객체에 추가
doc.addContent(rootNode);
/*
<? xml ... ?>
<부모노드>
<자식노드1 속성명1="속성값1">값1<자식노드1>
<자식노드2>값2</자식노드2>
<자식노드3>값3</자식노드3>
</부모노드>
*/
- 출력 객체 생성 후 출력
- 콘솔, 파일, 네트워크 등 다양하게 출력가능
XMLOutputter xout = new XMLOutputter();
xout.output(doc, 출력스트림);
- JDOM Parser로 XML 생성 예
public class CreateJdomXml {
public List<String> data() {
List<String> list = new ArrayList<String>();
list.add("월래 먹는 날");
list.add("화끈하게 먹는 날");
list.add("수도없이 먹는 날");
list.add("목이 터지게 먹는 날");
list.add("금새먹고 또 먹는 날");
list.add("토하면서 먹는 날");
list.add("일일이 찾아다니며 먹는 날");
return list;
}
public Document createXML(List<String> weekMsg) {
// 1. XML 문서객체 생성
Document doc = new Document();
// 2. 최상위 부모 노드를 생성
Element rootNode = new Element("week");
Element msgNode = null;
for(String data : weekMsg) {
// 3. 자식노드를 생성
msgNode = new Element("msg");
// 4. 자식 노드에 들어갈 값 설정
msgNode.setText(data);
// 5. 값을 가진 자식 노드를 부모 노드에 할당
rootNode.addContent(msgNode);
}
// 6. 자식노드를 가진 부모노드를 XML 문서객체에 추가
doc.addContent(rootNode);
return doc;
}
public void createXMLFile(Document doc) throws IOException {
// 7. 출력 객체 생성
XMLOutputter xout = new XMLOutputter();
// 8. XML 문서객체와 출력스트림을 사용하여 출력
xout.output(doc, System.out);
}
public static void main(String[] args) {
CreateJdomXml c = new CreateJdomXml();
try {
c.createXMLFile(c.createXML(c.data()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 출력객체로 출력할 때 format을 설정가능
- compact, raw format - 한줄로 출력
- pretty format - 줄바꿔 출력
// 7. 출력 객체 생성
// XMLOutputter xout = new XMLOutputter(Format.getCompactFormat());
// XMLOutputter xout = new XMLOutputter(Format.getRawFormat());
XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
public void createXMLFile(Document doc) throws IOException {
// 7. 출력 객체 생성
XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
// 8. XML 문서객체와 출력스트림을 사용하여 출력
xout.output(doc, new FileOutputStream("C:/.../jdom.xml"));
}
- 속성 있을 때, XML 생성 예
public class DataVO {
private String carModel, company, owner, carType; // carType을 속성으로 줄 것
private int cc;
... // 기본생성자, 인자있는 생성자, setter, getter
public class CreateJdomAttrXml {
public List<DataVO> data() {
List<DataVO> list = new ArrayList<DataVO>();
list.add(new DataVO("아반테", "현대", "김정윤", "승용", 1600));
list.add(new DataVO("솔리드프로", "넥슨", "김희철", "스포츠카", 3000));
list.add(new DataVO("연습용카트", "넥슨", "공선의", "스포츠카", 800));
list.add(new DataVO("소렌토", "기아", "이재찬", "SUV", 4800));
list.add(new DataVO("MAN트럭", "MAN", "노진경", "트럭", 10000));
return list;
}
public Document createXML(List<DataVO> carList) {
// 1. XML 문서객체 생성
Document doc = new Document();
// 2. 최상위 부모노드를 생성
Element rootNode = new Element("cars");
// 자식노드 선언
Element carNode = null;
Element carModelNode = null;
Element companyNode = null;
Element ownerNode = null;
Element ccNode = null;
// 속성 선언
Attribute carTypeAttr = null;
for(DataVO data: carList) {
// 3. 자식노드를 생성, 4. 값 설정
carNode = new Element("car");
carModelNode = new Element("model");
carModelNode.setText(data.getCarModel());
companyNode = new Element("company");
companyNode.setText(data.getCompany());
ownerNode = new Element("owner");
ownerNode.setText(data.getOwner());
ccNode = new Element("cc");
ccNode.setText(String.valueOf(data.getCc()));
// 속성 선언
carTypeAttr = new Attribute("type", data.getCarType());
// 속성 설정
carNode.setAttribute(carTypeAttr);
// 5. 값을 가진 자식 노드를 부모 노드에 할당
// car 노드에 자식노드 추가
carNode.addContent(carModelNode);
carNode.addContent(companyNode);
carNode.addContent(ownerNode);
carNode.addContent(ccNode);
// 자식 노드를 가진 car노드를 최상위 부모노드에 배치
rootNode.addContent(carNode);
}
// 6. 자식노드를 가진 부모노드를 XML 문서객체에 추가
doc.addContent(rootNode);
return doc;
}
public void createXMLFile(Document doc) throws IOException {
// 7. 출력 객체 생성, compact, raw format은 한줄로 출력
XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
// 8. XML 문서객체와 출력스트림을 사용하여 출력
// xout.output(doc, System.out);
xout.output(doc, new FileOutputStream("C:/.../jdom_car.xml"));
}
}
DTD(Document Type Definition)
- DTD도 하나의 XML, 확장자만 DTD
- XML 작성 규칙을 설정하는 일을 함
- DTD 없는 XML은 Well-Formed Document(적격문서)
- DTD 있는 XML은 Valid Document(유효문서)
- Valid Document는 작성규칙과 DTD에 정의된 규칙을 모두 지켜서 만들어야 한다.
- DTD를 사용한 XML이 작성규칙을 지키지 않으면 Error가 발생
- 복잡한 제어를 할 때에는
XML Schema
작성 - 작성 규칙 - 태그의 등장순서, 등장 횟수, 속성 정보
- 간단한 구조를 가진다
- 기호를 가지고 설정
- 사용 기호
- 작성법
- 노드명이 중복되면 가장 마지막 선언된 것만 들어간다.
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT 노드명 (자식노드명,...)> <!-- 노드와 자식노드 정의, ()안, 뒤에 기호사용 -->
<!ELEMENT 자식노드명 (#PCDATA)>
...
<!ATTLIST 노드명 속성명 CDATA #REQUIRE> <!-- 속성 정의, #~는 사용옵션 -->
<!ATTLIST 노드명 속성명 CDATA #FIXED "고정값">
<!ATTLIST 노드명 속성명 CDATA #IMPLIED>
- 필요한 XML에서 선언부를 정의하여 DTD를 사용한 XML 작성
<?xml version="1.0" encoding="UTF-8" standalone="false"?>
<!DOCTYPE 적용할노드명 SYSTEM "test.dtd">
<노드명>
<자식노드명>
...
- DTD 사용 예 1 - hello.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT root (msg*)>
<!ELEMENT msg (#PCDATA)>
- DTD 사용 예 1 - hello.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE root SYSTEM "hello.dtd">
<root>
<msg>안녕 XML!</msg>
<msg>오늘은 화요일이야</msg>
</root>
- DTD 사용 예 2 - depts.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT depts (dept+)>
<!ELEMENT dept (deptno?, dname+, loc*)>
<!ELEMENT deptno (#PCDATA)>
<!ELEMENT dname (#PCDATA)>
<!ELEMENT loc (#PCDATA)>
- DTD 사용 예 2 - depts.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE depts SYSTEM "depts.dtd">
<!-- 부서 정보를 저장하는 XML -->
<depts>
<dept>
<deptno>10</deptno>
<dname>SI 개발부</dname>
<loc>서울</loc>
</dept>
<dept>
<deptno>20</deptno>
<dname>SM 유지보수</dname>
<loc>경기</loc>
</dept>
<dept>
<deptno>30</deptno>
<dname>SE</dname>
<loc>서울</loc>
</dept>
<dept>
<deptno>40</deptno>
<dname>QA</dname>
<loc>부산</loc>
</dept>
</depts>
- DTD 사용 예 3 - computer.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT computers (computer)*>
<!ELEMENT computer (cpu+, motherBoard?, ram+, powerSupply+, (hdd?|sdd?), odd?, vga?)>
<!ELEMENT cpu (#PCDATA)>
<!ELEMENT motherBoard (#PCDATA)>
<!ELEMENT ram (#PCDATA)>
<!ELEMENT powerSupply (#PCDATA)>
<!ELEMENT hdd (#PCDATA)>
<!ELEMENT sdd (#PCDATA)>
<!ELEMENT odd (#PCDATA)>
<!ELEMENT vga (#PCDATA)>
<!ATTLIST cpu brand CDATA #REQUIRED>
<!ATTLIST motherBoard brand CDATA #REQUIRED>
<!ATTLIST hdd brand CDATA #REQUIRED>
<!ATTLIST vga brand CDATA #FIXED "NVIDIA">
- DTD 사용 예 3 - computer.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE computers SYSTEM "computer.dtd">
<computers>
<computer>
<cpu brand="intel">i5 3.3GHz</cpu>
<motherBoard brand="GIGABYTE">GM001</motherBoard>
<ram>16GB</ram>
<powerSupply>7team</powerSupply>
<hdd brand="WD">1TB</hdd>
<odd>LG</odd>
<vga brand="NVIDIA">GTX2080Ti</vga>
</computer>
</computers>