---
title: "Java EE 정리 20"
date: "2019-03-26"
tags: ["Java EE","XML"]
status: archived
verified: false
---

---

## XML(eXtensible Markup Language)

* **데이터의 구조를 표현하는 태그 언어**
* W3C에서 표준안을 제정, 발표
* **태그를 사용자가 정의하고 사용**
  * SGML에서 파생됨
    * HTML과 다르게 XML은 DTD가 없음        
        * 태그글 사용자가 마음대로 정의가능
        * 통일성이 없어 Parsing이 어렵다
          * DTD 필요성이 대두됨
* **이기종 언어간의 데이터 전달을 목적으로 사용**
  * XML로 다른 언어끼리 교류가능
    * C &lt;-> Java
    * Java &lt;-> JavaScript
    * Python &lt;-> Java
  * **XML 태그(노드)사이 값을 가져오는 작업을 Parsing이라고 한다.**

```html
<노드명>값</노드명>
```

* **프로그램에서 사용할 값을 저장**
  * 환결설정 목적 (Tomcat server.xml, web.xml 등)
  * 국제화 목적 (똑같은 프로그램 여러 언어로 설정)
* 데이터 구조를 잘 표현하는 언어
  * 사용자에게 보여지는 용도가 아님
* **HTML과 다르게 Error 발생**
* **시작 노드와 끝 노드는 반드시 쌍으로 존재해야 된다**
* **대소문자 구분**
* **최상위 부모 노드는 하나만 작성 가능**
* **Well-Formed Document(적격 문서)**
  * **DTD없이 작성하는 XML**
  * 작성 규칙만 지켜서 만든 XML
* **Valid Document(유효 문서)**
  * **DTD를 정의하고 참조하여 작성하는 XML**
  * 작성 규칙과 DTD의 정의규칙을 지켜 만드는 XML
* **보통 DB의 레코드를 XML로 바꿔 사용**
  * 공공데이터의 결과를 XML로 많이 제공
  * XML보다 JSON이 보편화 되고 있음

## XML 작성법 

* **선언부 - 무조건 첫줄에 나와야 한다**
  * standalone은 DTD여부 (yes/no)

```html
<?xml version="1.0" encoding="UTF-8" standalone="yes|no"?>
```

* **DTD가 존재하면**
  * **SYSTEM**은 DTD가 내 HDD에 있을 때
  * **PUBLIC**은 DTD가 다른 웹 서버에 있을 때

```html
<!DOCTYPE 적용노드명 SYSTEM "DTD의 위치">
<!DOCTYPE 적용노드명 PUBLIC "DTD의 URL">
```

* **부모노드는 XML에서 딱 1개 존재**
  * DOM tree - 태그를 트리형태로 그린 것

```html
<부모노드>
    <자식노드>
    ...
    </자식노드>
</부모노드>
```

```html
<depts>
    <dept>
        <dname>SI</dname>
        <loc>서울</loc>
        <deptno>10</deptno>
    </dept>
    <dept>
        <dname>SM</dname>
        <loc>대구</loc>
        <deptno>20</deptno>
    </dept>
    <dept>
        <dname>SE</dname>
        <loc>부산</loc>
        <deptno>30</deptno>
    </dept>
</depts>
```

![07](/md/legacy-assets/javaEe/20/07.webp)

* **XML 사용 예**

```html
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
      <msg>안녕 XML!</msg>
      <msg>오늘은 화요일이야</msg>
</root>
```

![01](/md/legacy-assets/javaEe/20/01.webp)


![02](/md/legacy-assets/javaEe/20/02.webp)

* **XML에서 에러가 발생하는 경우들**

```html
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- 선언부가 첫 라인에 없으면 에러 -->
<root>
      <msg>안녕 XML!</msg>
      <msg>오늘은 화요일이야</msg>
      <!-- <msg>닫힘노드가 없으면 에러 -->
      <!-- <Hello>대소문자 가린다</hello> -->
      <msg/><!--  Element 사이에 값이 없다면/로 하나의 태그만 작성할 수  있다. -->
</root>
<!-- 최상위 부모노드는 반드시 하나만 존재해야 한다.
<root>
</root>
-->
```


* **사람의 정보를 저장하는 XML 만들기**
  * XML의 장점은 데이터의 정보를 명확히 알 수 있다.

```html
<?xml version="1.0" encoding="UTF-8"?>
<people>
      <person>
            <name>
                  <firstName>영근</firstName>
                  <lastName>오</lastName>
            </name>
            <ssn>990133-*******</ssn>
            <address>서울 강동구</address>
      </person>
      <person>
            <name>
                  <firstName>민지</firstName>
                  <lastName>김</lastName>
            </name>
            <ssn>871112-*******</ssn>
            <address>서울 서초구</address>
      </person>
      <person>
            <name>
                  <firstName>소소</firstName>
                  <lastName>손</lastName>
            </name>
            <ssn>930812-*******</ssn>
            <address>서울 관악구</address>
      </person>
</people>
```

![03](/md/legacy-assets/javaEe/20/03.webp)

* **XML을 Java로 Parser없이 Parsing하기**

```java
// 1. a.xml과 Stream 연결
BufferedReader br = new BufferedReader(new FileReader("xml의 경로"));

// 2. 줄단위로 끝까지 읽어들이기
String temp = "";
String data = "";
while((temp = br.readLine()) != null) {
    
    // 3. 원하는 태그인지를 판단
    if (temp.contains("<name>")) {
        
        // 4. Parsing
        data += temp.substring(temp.indexOf(">")+1, temp.lastIndexOf("<"));
    }
} 
```

```html
<%!
public List<String> xmlParsing() throws IOException  {
      
      List<String> list = new ArrayList<String>();
      BufferedReader br = null;
      
      try {
            // 1. XML과 연결
            File file = new  File("C:/.../xml0326/names.xml");
            br = new BufferedReader(new InputStreamReader(new  FileInputStream(file),"UTF-8"));
            
            String temp = "";
            String name = "";

            // 2. 줄단위로 읽어들인다.
            while((temp = br.readLine()) != null) {
                  if (temp.contains("<name>")) { // name노드가 이 있다면
                        name = temp.substring(temp.indexOf(">")+1,  temp.lastIndexOf("<"));
                        
                        list.add(name);
                  }
            }
            
      } finally {
            if (br != null) { br.close(); }
      }
      
      return list;
}
%>

<table border="1">
<tr>
      <th width="100">이름</th>
</tr>
<c:forEach var="name" items="<%= xmlParsing() %>">
<tr>
      <td style="text-align: center;"><c:out value="${ name }"/></td>
</tr>
</c:forEach>
</table>
```

![04](/md/legacy-assets/javaEe/20/04.webp)

## JDOM (XML Parser) 설치

* [JDOM 사이트](http://jdom.org/)
* **Downloads - Binaries - JDOM 2.0.6 다운로드**

![05](/md/legacy-assets/javaEe/20/05.webp)

* **jdom-2.0.6.jar를 WEB-INF/lib에 옮김**

![06](/md/legacy-assets/javaEe/20/06.webp)

## XML Parser
* **XML을 Parsing할 수 있는 도구**
* **SAX(Simple API for XML) 방식 Parser**
  * **줄 단위로 XML을 분석하는 Parsing 도구**
  * sun사에서 제안
* **DOM(Document Object Model) 방식 Parser**
  * **Node를 객체로 만들어 작업**
  * IBM사에서 제안
  * DOM방식이 사용상 편의성이 더 좋다
* **JDOM은 두가지 방식을 혼합해서 만들어진 Parser**
  * [JDOM Doc](http://jdom.org/docs/apidocs/)
* **JDOM Parser 사용법**

```java
// 1. builder 생성
SAXBuilder sb = new SAXBuilder();

// 2. XML을 문서 객체로 저장
// File이나 URL 등 어디서든 접근가능하도록 Overloading 되어있다.
Document doc = sb.build(new URL("http://.../ooo.xml ")); 

// xml자체가 doc이란 객체에 들어간 것
// 3. 최상위 부모 노드를 얻는다.
Element rootNode = doc.getRootElement();

// 4. 자식 노드들을 얻는다.
// List<Element> deptNodes = rootNode.getChildren(); // for문 사용가능
// 더 빠른 Iterator 사용 예
Iterator<Element> deptNodes = rootNode.getChildren().iterator();

// 5. 자식 노드들을 순환
Element someNode = null;
String nodeName = "";
String nodeVal = "";

while(deptNodes.hasNext()) {
    // 6. 자식노드 얻기
    someNode = deptNodes.next();

    // 7. 노드명 구하기
    nodeName = someNode.getName();

    // 8. 노드값 구하기
    nodeVal = someNode.getText();
}
// 이렇게 원하는 값 뽑아내서 사용
```

* **JDOM Parser 사용 예**

```java
/**
* JDOM Parser 사용
*/
public class UseJDOMParser {
      
      public UseJDOMParser() throws MalformedURLException,  JDOMException, IOException {
            
            // 1. Parser 생성
            SAXBuilder sb = new SAXBuilder();
            
            // 2. XML를 문서객체에 저장
            Document doc = sb.build(new URL("http://localhost:8080/jsp_prj/xml0326/names.xml"));
            
            // 3. 문서객체에서 최상위 부모 노드를 얻기
            Element rootNode = doc.getRootElement();
            
            // 4. 부모노드로부터 자식 노드들 얻기
            Iterator<Element> nameNodes =  rootNode.getChildren().iterator();
            
            Element nameNode = null;
            // 5. 자식노드 순환
            while(nameNodes.hasNext()) {
                  // 6. 자식 노드 얻기
                  nameNode = nameNodes.next();
                  System.out.println("노드명 : " + nameNode.getName());
                  System.out.println("노드값 : " + nameNode.getText());
            }
      }
      
      public static void main(String[] args) {
            try {
                  new UseJDOMParser();
            } catch (MalformedURLException e) {
                  e.printStackTrace();
            } catch (JDOMException e) {
                  e.printStackTrace();
            } catch (IOException e) {
                  e.printStackTrace();
            }
      }
}
```

![08](/md/legacy-assets/javaEe/20/08.webp)

## RSS Parsing

* [JTBC 속보 xml](http://fs.jtbc.joins.com//RSS/newsflash.xml)
  
![09](/md/legacy-assets/javaEe/20/09.webp)

* **데이터를 담을 VO 생성**

```java
public class RssVO {
      private String title, link, description, pubDate;
      // getter, setter, 기본생성자
      ...
```

* **Parsing을 할 싱글톤패턴 적용한 클래스**

```java
public class JtbcRssParsing {
      private static JtbcRssParsing jrp;
      
      private JtbcRssParsing() {}
      public static JtbcRssParsing getInstance() {
            if (jrp == null) {
                  jrp = new JtbcRssParsing();
            }
            
            return jrp;
      }
      
      public List<RssVO> getNews(String rssName) throws IOException,  JDOMException {
            List<RssVO> list = new ArrayList<RssVO>();
            
            StringBuilder xmlURL = new StringBuilder();
            xmlURL.append("http://fs.jtbc.joins.com/RSS/");
            
            if(rssName != null || "".equals(rssName)) {
                  xmlURL.append(rssName).append(".xml");
            } else {
                  xmlURL.append("newsflash.xml");
            }
            
            // 1. Builder 생성
            SAXBuilder sb = new SAXBuilder();
            
            // 2. URL로 외부 서버에서 제공하는 RSS 문서 객체 얻기
            Document doc = sb.build(new URL(xmlURL.toString()));
            
            // 3. 최상위 부모노드 얻기
            Element rootNode = doc.getRootElement(); // rss
            
            // 4. 자식 노드(channel) 얻기
            Element channelNode = rootNode.getChild("channel");
            
            // 5. channel노드의 자식 노드들 얻기
            Iterator<Element> someNodes =  channelNode.getChildren().iterator();
            
            Element someNode = null;
            Iterator<Element> itemSubNodes = null;
            Element itemSubNode = null;
            RssVO rvo = null;

            // channel 노드의 자식 노드들을 순환
            while(someNodes.hasNext()) {
                  
                  someNode = someNodes.next();
                  if("item".equals(someNode.getName())) { 
                        itemSubNodes =  someNode.getChildren().iterator();
                        
                        rvo = new RssVO();
                        // item 노드의 자식 노드들을 순환
                        while(itemSubNodes.hasNext()) {
                              itemSubNode = itemSubNodes.next();
                              
                              if ("title".equals(itemSubNode.getName()))  {
                                    rvo.setTitle(itemSubNode.getText());
                              }
                              if ("link".equals(itemSubNode.getName()))  {
                                    rvo.setLink(itemSubNode.getText());
                              }
                              if  ("description".equals(itemSubNode.getName())) {
                                    rvo.setDescription(itemSubNode.getText());
                              }
                              if  ("pubDate".equals(itemSubNode.getName())) {
                                    rvo.setPubDate(itemSubNode.getText());
                              }
                        }
                        // 순환 하며 RssVO에 setter로 값할당 후 list에 저장, 반복
                        list.add(rvo);
                  }
            }
            
            return list;
      }
}
```

```html
<!-- jtbc_rss.jsp -->
<style type="text/css">
...
      td {
            padding-left:3px;
      }
</style>
...
<div id="subject" style="text-align:center;">
[ <a href="jtbc_rss.jsp?title=newsflash">속보</a>     |
<a href="jtbc_rss.jsp?title=politics">정치</a> |      
<a href="jtbc_rss.jsp?title=economy">경제</a>   |
<a href="jtbc_rss.jsp?title=society">사회</a> |
<a href="jtbc_rss.jsp?title=international">국제</a> |
<a href="jtbc_rss.jsp?title=culture">문화</a>   |
<a href="jtbc_rss.jsp?title=entertainment">연예</a> |
<a href="jtbc_rss.jsp?title=sports">스포츠</a> |
<a href="jtbc_rss.jsp?title=fullvideo">풀영상</a> |   
<a href="jtbc_rss.jsp?title=newsrank">뉴스랭킹</a>    |
<a href="jtbc_rss.jsp?title=newsroom">뉴스룸</a>      |
<a href="jtbc_rss.jsp?title=morningand">아침&amp;</a> |     
<a href="jtbc_rss.jsp?title=newssite">뉴스현장</a>    |
<a href="jtbc_rss.jsp?title=politicaldesk">정치부회의</a> ]
</div>

<div id="newsView">
<%
      String rssName = request.getParameter("title");

      if (rssName == null) {
            rssName = "newsflash";
      }

      List<RssVO> list = JtbcRssParsing.getInstance().getNews(rssName);
      
      pageContext.setAttribute("newsList", list);
%>
<c:if test="${ empty newsList }">
네트워크가 연결이 불안정합니다. 잠시 후 다시 시도해주세요.
</c:if>

<c:forEach var="news" items="${ newsList }">
<table style="border:1px solid #333; border-spacing:0px; margin:0px  auto; margin-top:6px; ">
<tr>
      <td style="width:50px; text-align:center; border-right:1px solid  #333;">제목</td>
      <td colspan="3" style="width:650px; text-align:center">
            <c:out value="${ news.title }"/>
      </td>
</tr>
<tr>
      <td style="width:50px; text-align:center; border-right:1px solid  #333;">링크</td>
      <td><a href="${ news.link }" target="_new">뉴스이동</a></td>
      <td style="width:50px; text-align:left;">작성일</td>
      <td><c:out value="${ news.pubDate }"/></td>
</tr>
<tr>
      <td style="width:50px; text-align:center; border-right:1px solid  #333;">내용</td>
      <td colspan="3" style="width:650px;">
            <c:out value="${ news.description }"/>
      </td>
</tr>
</table>
</c:forEach>
</div>
```

![10](/md/legacy-assets/javaEe/20/10.webp)
