프로그래밍/XML2010. 4. 4. 18:05

DOM을 이용한 메타데이터 추출             
                                                                                                                        
                                                                                              

작성자 : 김 인희(kevin@asc.co.kr)

Summary
일반적으로 웹사이트 구축시 테이블 이름이나 sql구문 또는 여러 (사용자가 정의한)코드값들을 그대로 코드에 집어 넣는다. 그리고 웹페이지에서 보여지는 여러 텍스트들도 그대로 코드에 넣는 경향이 있다. 물론 소규모의 프로젝트시에는 문제가 없으나 프로젝트가 커질수록 웹사이트를 유지, 보수하기가 어려워진다. 그래서 xml과 자바를 연동시켜서 위에서 나열한 메타 데이터를 얻는 방법을 소개할까 한다.

---------------------------------------------------------------------------------------------------------


xml은 단지 데이터이기 때문에 xml을 처리하기 위해서는 파싱 과정이 필요하다. 따라서 xml을 사용하는 애플리케이션은 각각의 데이터에 접근하고 처리하기 위한 수단이 필요하다. 그러한 기능을 가지고 있는 것이 SAX와 DOM이다.


SAX 
SAX는 'Simple API for xml'을 의미하며, 그 이름 그대로 xml을 위한 간단한 API를 제공한다. SAX는 xml 데이터를 분석하기 위한 이벤트 기반의 구조를 제공하며, 이러한 구조는 크게 문서를 읽어나가는 과정과 데이터를 사용할 수 있는 부분으로 분리된다. 이벤트는 xml 문서를 순차적으로 처리하는 동안 각 단계에서 발생하며, SAX는 각 이벤트가 발생할 때 호출되는 메소드를 정의하고 있다. 예를 들어, 한 요소의 여는 태그를 만날 경우 startElement() 메소드를 호출하며, 끝 태그를 만날 경우 endElement() 메소드를 호출한다.
SAX는 문서를 읽어나가는 과정에서 발생하는 이벤트를 위한 인터페이스 뿐만 아니라, 잘못된 문서나 비적격(non well-formed) 문서와 같이 xml을 분석하는 과정에서 발생할 수 있는 다양한 상황을 처리할 수 있도록 해 주는 에러와 경고 집합을 정의하고 있다.

 

DOM  
DOM은 'Document Object Model'을 의미한다. SAX가 단지 xml 문서의 데이터에 접근하기 위한 방법을 제공한다면, DOM은 그러한 데이터를 처리하는 방법을 제공하기 위해 설계되었다. DOM은 xml 문서를 트리 형태로 표현한다. 자바를 비롯한 프로그래밍 언어에서는 트리 구조를 쉽게 순회하고 처리할 수 있기 때문에, DOM 트리(xml 문서를 DOM으로 표현한 것을 DOM 트리라고 부른다)를 쉽게 처리할 수 있다. SAX와 달리 DOM은 전체 xml 문서를 메모리에 읽어온 후에 DOM 트리를 구성하기 때문에, 한번 문서를 읽으면 매우 빠르게 전체 문서에 접근할 수 있다.
DOM이 전체 xml 문서를 메모리에 읽어온 후에 DOM 트리를 작성한다는 것이 빠르게 xml 문서의 각 요소에 접근할 수 있다는 장점을 제공하긴 하지만, 반면에 결정적인 단점을 제공하기도 한다. DOM은 xml 문서의 크기에 비례한 메모리를 필요로 하기 때문에, xml 문서의 크기가 커질수록 많은 메모리를 요구하게 된다. xml 문서의 매우 클 경우 이는 매우 많은 양의 시스템 자원을 사용하게 되며, 따라서 시스템의 전체적인 성능 저하 현상을 일으키기도 한다
먼저 각종 코드값을 가지고 있는 xml 문서를 살펴보자.

 

xml 문서(codeSubset.xml)


<?xml version = "1.0" encoding="EUC-KR"?>
<Config> 
 <TableCode>
             <Table code="111">CounselData</Table>
             <Table code="222">KcabBoard</Table>
 </TableCode>
 <JobList>
             <Job code="50">전체</Job>
             <Job code="51">법조계</Job>
   <Job code="52">실업계</Job>
             <Job code="53">학계</Job>
 </JobList>
</Config>

 

코드는 각 엘리먼트의 속성값에 넣었다. 그리고 코드값은 엘리먼트의 양쪽 태그사이에 두었다. xml1.0 스펙에 따르면 태그 사이에 있는 데이터는 문자데이터(character data)이다. 
다음으로 위 xml 문서를 처리해서 코드에 해당하는 코드값을 얻어오는 프로그램을 작성해보자. 여기서는 DOM을 이용할것이다. xml 파 서로는 Apache Xerces(<
http://xml.apache.org>) 파서를 사용하였다. Xerces 파서를 다운 받은다음 클래스패스에 추가하면 된다. 
다음 코드를 살펴보자. 


import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Document; 
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.CharacterData;
//import org.apache.xerces.dom.TextImpl;


public class xmlMgr {
           /*
           * 주어진 xml를 찾아 파서로 파싱을 하고 Document를 리턴한다
           */
           private Document getDocument(String uri) {
                       System.out.println("Parsing xml file: "  + uri + "\n");
                       
                       DOMParser parser = new DOMParser();
                       Document doc = null;
                       
                       try {
                                   parser.parse(uri);
                                   doc = parser.getDocument();
                                   
                       } catch(Exception e) {
                                   System.out.println("Error in Parsing : " + e.getMessage());
                       }
                       return doc;
                       
           }
           /*
           * @param uri xml 문서가 위치한 URL
           * @param nodeName 노드 이름
           * @param codeValue 코드값
           */
           public String getConfig(String uri, String nodeName, String codeValue) {
           
                       NodeList nodeList = getNodeList(uri, nodeName);
                       
                       String returnValue = "";
                       /*
                       * 각 노드에 해당하는 속성을 가지고 있는
                       * NamedNodeMap를 얻고 코드에 해당하는 
                       * 코드값을 얻는다
                       */
                       if(nodeList != null) {
                                   for(int i = 0; i < nodeList.getLength(); i++) {
                                               Node node = nodeList.item(i);
                                               NamedNodeMap attributes = node.getAttributes(); 
                                               for(int j = 0; j < attributes.getLength(); j++) {
                                                           Node current = attributes.item(j);
                                                           if(current.getNodeValue().equals(codeValue)) {
                                                                       returnValue = getValue(node.getChildNodes());
                                                           }
                                                           
                                               }
                                   }
                       }
                       return returnValue;            
                                   
           }
           
           private String getValue(NodeList children) {
                       
                       String returnValue = "";
                       if(children != null) {
                                   for(int i = 0; i < children.getLength(); i++) {
                                               returnValue = children.item(i).getNodeValue();
                                   }
                       }
                       return returnValue;
                       
           } 


           /*
           * 주어진 파일이름에 해당하는 Document를 통해
           * 노드이름과 일치하는 NodeList를 얻는다.
           */
           private NodeList getNodeList(String uri, String nodeName) {
                       
                       NodeList returnNodeList = null;
                       Document doc = getDocument(uri);
                       returnNodeList = doc.getElementsByTagName(nodeName);
                       return returnNodeList;
                       
           }

 

코드 중간 중간에 주석을 삽입했기 때문에 이해하는데 어려움은 없을 것이다. 실제로 위와 같은 방법은 상당히 유용한다. 만약
테이블 이름을 얻는다면 다음과 같이 하면 된다.

 

           xmlMgr objxmlMgr = new xmlMgr();
           String tableName = objxmlMgr.getConfig("codeSubset.xml", "Table", "111");

 

그러면 tableName는 "CounselData"를 얻을 것이다.

또 jsp내에서 코드값에 해당하는 텍스트를 얻을때도

 

           <%=objxmlMgr.getConfig("codeSubset.xml", "Job", "51")%>

 

이러한 방법을 사용하면 된다. 


자바와 xml을 연동함으로써 그동안 개발자에게 골치거리였던 유지, 보수 문제를 어느 정도 해결할 수 있다. 앞으로 자바와 xml연동
을 더 효과적으로 한다면 보다 향상된 웹애플리케이션을 작성할 수 있을 것이다.

 

Resources
           * javacan 페이지
                       (<
http://www.javacan.com>)
           * Java and xml (o'reilly)
           * xml Applications(Wrox)

 

궁금한 점이나 고쳐야 할 부분이 있으면 위의 메일 주소로 멜 날려 주세요.

반응형
Posted by 컴투
스포츠/야구2010. 4. 4. 17:53

(AP) 박찬호 첫 등판..1이닝 공 5개로 마무리박찬호 첫 등판..1이닝 공 5개로 마무리 (AP=연합뉴스) 박찬호(37)가 뉴욕 양키스 유니폼을 입고 공식 경기에 처음 등판했다. 박찬호는 19일(이하 한국시간) 미국 플로리다주 탬파의 조지 스타인브레너 필드에서 열린 탬파베이 레이스와 시범경기에 중간 계투 투수로 나와 1이닝 동안 세 타자를 깔끔하게 막았다. 사진은 박찬호가 지난 1일 미국 플로리다주 탬파의 조지 스타인브레너 필드에서 열린 시범경기에서 투구하는 모습. 2010.3.19

(서울=연합뉴스) 장현구 기자 = 박찬호(37.뉴욕 양키스)와 추신수(28.클리블랜드 인디언스)가 미국프로야구 시범경기를 성공적으로 마무리하고 정규 시즌 출격 준비를 마쳤다.

박찬호와 추신수는 4일(한국시간) 열린 마지막 시범경기인 뉴욕 양키스 퓨처스(마이너리그), 신시내티 레즈와 경기에 나란히 결장했다. 팀의 주축인 둘은 시즌 개막에 맞춰 컨디션을 조율했다.

한 달간 진행된 시범경기를 마친 둘은 5일부터 팀당 162경기씩 6개월 간 대장정을 시작한다.

박찬호는 5일 오전 9시5분 매사추세츠주 보스턴의 펜웨이파크에서 보스턴과 공식 개막전에 나서고 추신수는 6일 새벽 3시5분 일리노이주 시카고 US셀룰러 필드에서 시카고 화이트삭스와 첫 경기를 벌인다.

1년간 최대 150만달러를 받고 양키스 유니폼을 입은 박찬호는 계약이 늦어져 지난달 1일에서야 팀에 합류했지만 시범 경기 6경기에서 7이닝 동안 1점도 주지 않는 무결점 투구로 베테랑다운 위력을 뽐냈다.

삼진은 8개를 잡았고 볼넷은 1개도 허용하지 않는 등 마무리 투수 바로 앞에 등판하는 8회 셋업맨으로서 자질을 인정받았다.

조 지라디 양키스 감독이 아직 보직을 확실히 구분 짓지는 않았지만 박찬호는 시범경기에서 호투를 발판삼아 조바 챔벌레인, 데이비드 로버트슨과 집단 셋업맨 체제를 구축할 것으로 보인다.

지난해 통산 27번째 월드시리즈 우승컵을 가져간 양키스가 올해도 가장 강력한 우승 0순위 후보로 거론되면서 빅리그 17년차 박찬호의 첫 우승반지 꿈도 무르익어가고 있다.

추신수(사진 오른쪽)(AP=연합뉴스)

'추추 트레인' 추신수의 방망이도 시범경기부터 쉴 새 없이 펑펑 터졌다.

풀타임을 처음으로 뛴 지난해 타율 0.300을 때리고 20홈런에 21도루를 기록, 아메리칸리그 선수 중 유일하게 타율 3할과 20-20 클럽을 동시에 달성했던 추신수는 시범경기에서 홈런(3개), 타점(16개) 팀 내 1위를 차지하며 해결사의 입지를 굳혔다.

붙박이 우익수를 꿰찬 추신수는 3번 타자로 중용됐고 19경기에서 타율 0.393(56타수22안타)이라는 고감도 손맛을 자랑했다.

6경기에서 안타 2개 이상을 때려내는 등 꾸준한 활약을 펼쳤고 안타 22개 중 10개가 2루타 이상의 장타였을 정도로 물오른 장타율(0.696)을 선보였다.

주로 밀어서 안타를 생산하는 등 '부챗살 타법'으로 정교함과 파워를 동시에 보여줘 올해 맹활약을 예감케 했다.

구단의 장기 계약 제안도 마다하고 1년간 최소 연봉 수준인 45만달러에 계약한 추신수는 다치지 않고 지난해 이상의 성적을 낸다면 11월 광저우 아시안게임 대표팀에 당당히 뽑힐 것으로 보인다.

금메달을 따내 병역 혜택을 받는다면 호타준족 추신수의 몸값은 내년 이후 폭등할 것으로 점쳐진다.

cany9900@yna.co.kr

반응형
Posted by 컴투
프로그래밍/XML2010. 4. 4. 17:43

다음의 인코딩은 모두 "한글 완성형"을 의미합니다.

* cp949
* MS949
* euc-kr
* ks_c_5601-1987

cp949 와 MS949 는 MS에서 만든 "한글 확장 완성형"이고, 그래서 "똠방각하" "전홥니다" 의 "똠"자나 "홥"자를 사용할 수 있습니다. MS윈도우에서 사용하는 기본 인코딩이 cp949 입니다. (물론 Windows 내부적으로는 유니코드 UTF-16LE 를 사용)

euc-kr 과 ks_c_5601-1987 은 그냥 "한글 완성형"이기에, 똠방각하 등을 쓸 수 없어야 하지만, 현재는 "확장 완성형"과 사실상 동일한 인코딩으로서 사용되므로 표현할 수 있습니다.

다만 Perl(펄)에서는 cp949 가 아닌 euc-kr 로 지정하면, 똠방각하가 나오지 않습니다: ▶▶ [펄 프로그래밍] Perl/Tk 에서, 한글 사용하기; 한글 인코딩



즉, 현재 모든 한글 인코딩은 확장 완성형입니다. (물론 한글 유니코드일 경우에는, 확장 완성형이나 그냥 완성형과는 호환되지 않습니다.)


한글 확장 완성형으로 HTML 파일을 만들 때에는 euc-kr 이라는 이름으로 인코딩을 지정하는 것이 표준입니다. ks_c_5601-1987 이것은 표준이 아닙니다.




MS949 is not supported by the current VM operation system
만약 자바(JAVA)에서 이런 에러가 난다면, 자바 버전이 오래되어서 그럴 수도 있을 것입니다. Sun 에서 제공하는 최신 버전 (1.5 이상)의 자바를 설치해 보시기 바랍니다. ▶▶ [Java] 자바 런타임과 JDK(개발도구; 컴파일러) 파일 다운로드하는 곳은? / 자바의 종류는? [QnA]






업데이트
자바(Java)에서, cp949 나 euc-kr 로 인코딩을 지정하면, "똠방각하" 등이 표현되지 않습니다. 즉 "그냥 완성형"인 것입니다.

따라서 자바에서 똠방각하 등을 제대로 표현하기 위해서는, MS949 인코딩 즉 "한글 확장 완성형"을 사용해야 합니다.

다 만, Perl에서는 cp949 인코딩으로도 확장완성형이 출력됩니다.

[펌 ]http://mwultong.blogspot.com
반응형
Posted by 컴투