• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

    • About
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Java EE 정리 20

26 Mar 2019

Reading time ~6 minutes

Java EE 정리 20 - XML, JDOM Parser, RSS Parsing


XML(eXtensible Markup Language)

  • 데이터의 구조를 표현하는 태그 언어
  • W3C에서 표준안을 제정, 발표
  • 태그를 사용자가 정의하고 사용
    • SGML에서 파생됨
      • HTML과 다르게 XML은 DTD가 없음
        • 태그글 사용자가 마음대로 정의가능
        • 통일성이 없어 Parsing이 어렵다
          • DTD 필요성이 대두됨
  • 이기종 언어간의 데이터 전달을 목적으로 사용
    • XML로 다른 언어끼리 교류가능
      • C <-> Java
      • Java <-> JavaScript
      • Python <-> Java
    • XML 태그(노드)사이 값을 가져오는 작업을 Parsing이라고 한다.
<노드명>값</노드명>
  • 프로그램에서 사용할 값을 저장
    • 환결설정 목적 (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)
<?xml version="1.0" encoding="UTF-8" standalone="yes|no"?>
  • DTD가 존재하면
    • SYSTEM은 DTD가 내 HDD에 있을 때
    • PUBLIC은 DTD가 다른 웹 서버에 있을 때
<!DOCTYPE 적용노드명 SYSTEM "DTD의 위치">
<!DOCTYPE 적용노드명 PUBLIC "DTD의 URL">
  • 부모노드는 XML에서 딱 1개 존재
    • DOM tree - 태그를 트리형태로 그린 것
<부모노드>
    <자식노드>
    ...
    </자식노드>
</부모노드>
<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

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

01

02

  • XML에서 에러가 발생하는 경우들
<?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의 장점은 데이터의 정보를 명확히 알 수 있다.
<?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

  • XML을 Java로 Parser없이 Parsing하기
// 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("<"));
    }
} 
<%!
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

JDOM (XML Parser) 설치

  • JDOM 사이트
  • Downloads - Binaries - JDOM 2.0.6 다운로드

05

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

06

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
  • JDOM Parser 사용법
// 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 사용 예
/**
* 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

RSS Parsing

  • JTBC 속보 xml

09

  • 데이터를 담을 VO 생성
public class RssVO {
      private String title, link, description, pubDate;
      // getter, setter, 기본생성자
      ...
  • Parsing을 할 싱글톤패턴 적용한 클래스
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;
      }
}
<!-- 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



Java EEXML