XML을 저장하는 다양한 방법 - 3
  저 자 : 박준호
  출판일 : 2003년 7월호

  앞에서 보는 바와 같이 표현하고자 하는 XML 문서의 구조와 메모리 상의 정보 모델이 1:1로 맵핑이 되는 구조에서 쉽게 XPath의 API만을 이용하여 맵핑이 되는 것을 확인할 수 있다. 다음은 좀더 복잡한 구조에서 XML 문서를 로딩하는 방법을 예를 들어 보자.

XPath API를 이용하여 Dept.xml로부터 로딩하는 방법
사원 XML 문서와 달리 Dept.xml은 하나의 부서에 대한 정보와 부서내의 각 사원들의 정보를 같이 표현하고 있다. <그림 2>는 Dept XML 문서의 구조와 이를 변환하여 하나의 Dept 객체와 세 개의 Employee 객체로 변환한 결과를 나타낸다.



<그림 2> Dept.xml의 변환 과정



Dept XML의 구조를 보면 Employees라는 엘리먼트를 가지고 Employees 엘리먼트는 여러 개의 Employee 엘리먼트를 가진다. 이러한 구조를 자바 객체로 표현하기 위해 자바의 유틸리티 패키지의 Hashtable를 이용하면 여러 개의 데이터의 저장 및 검색에 용이하다. <리스트 3>은 Dept XML을 읽어서 Dept 객체를 생성하고 하위 Employee 객체를 여러 개 생성하여 Hashtable 형태로 저장하는 예를 나타낸다.

public class Dept {
// members
public String DeptNo;
public String DName;
public String Loc;

// employees
public Hashtable Employees=new Hashtable();

public Dept(Node node) throws Exception {
DeptNo =
XPathAPI.selectSingleNode(node,"Dept/DeptNo/text()").getNodeValue();
DName=XPathAPI.selectSingleNode(node,"Dept/DName/text()").getNodeValue();
Loc=XPathAPI.selectSingleNode(node,"Dept/Loc/text()").getNodeValue();

// XML 문서 구조에서 모든 Employee 노드들을 XPath를 이용하여 검색한다.
NodeList nl=XPathAPI.selectNodeList(node,"Dept/Employees/Employee");

// 검색된 Employee 노드 모두에 대해 Employee 생성자를 호출하여 Employee 객체를 생성한 후
// Hashtable Employees에 저장한다.
for(int i=0;i Employee emp = new Employee(nl.item(i));
Employees.put(emp.EmpNo, emp);
}
}

public static void main(String args[])
throws Exception{
Document document = XMLUtil.parse(new File("Dept.xml"));
Dept dept = new Dept(document);
}
}

더 복잡한 구조의 XML을 파일 시스템으로부터 로딩하는 방법
앞에서 XML 파일로부터 하나의 객체로 변환하는 방법과 여러 개의 객체로 변환하는 방법에 대해 살펴봤다. 더 복잡한 구조의 XML을 더 복잡한 정보 모델로 형성하는 방법 또한 앞 두 방법의 확장을 통해 가능하다. 단 이러한 방법을 사용할 경우 XML로 표현되는 모든 데이터는 객체들의 관계로 맵핑되어 대부분이 메모리에 로딩되므로 데이터의 양을 고려해야 하며, 메모리에 로딩된 정보들은 개발 언어의 여러 가지 데이터 모델을 이용하여 관리되므로 개발 언어가 지원하는 데이터 모델의 성능과 기능이 애플리케이션에서 요구하는 바에 충분한지를 판단해야 한다.

정보 모델에서 XML 문서의 내용을 변경하거나 검색하는 방법
앞에서 XML 문서를 파싱과 XPath 등을 이용하여 메모리 상의 정보 모델로 맵핑한 후에는 XML의 기술이 아닌 정보 모델에서 제공하는 여러 API를 이용하여 문서의 변경, 검색, 생성 등을 할 수 있다. <리스트 5>는 Dept XML 문서를 로딩한 후 이를 변경하거나 검색하는 방법 및 새로운 Dept 문서를 생성하기 위한 정보 모델을 만드는 API를 나타낸다. 정보 모델은 메모리에 존재하게 되므로 변경된 정보는 다시 XML로 저장돼야 한다.

. . .
public class Dept {
. . .
// 생성 : 프로그래밍 언어의 객체 생성 방법을 그대로 이용하여 Dept 객체를 생성
public Dept(String _DeptNo, String _DName,String _Loc, Hashtable _Employees){
this.DeptNo = _DeptNo;
this.DName = _DName;
this.Loc = _Loc;
this.Employees = _Employees;
}

// 변경 : 간단한 API로 데이터 변경
public void setDeptNo(String DeptNo) {this.DeptNo = DeptNo;}
public void setDName(String DName) { this.DName = DName; }
public void setLoc(String Loc) {this.Loc = Loc;}
public void setEmployees(Hashtable Employees) {
this.Employees = Employees;
}

// 검색 : Hashtable을 이용한 메모리 상의 빠른 검색
public Employee findEmployee(String EmpNo) {
Employee emp = (Employee)Employees.get(EmpNo);
return emp;
}
. . .
}



정보 모델에서 XML 파일을 저장하는 방법
정보 모델을 다시 XML로 저장하는 방법을 살펴보고자 한다. <화면 1>에서 정보 모델로부터 XML을 생성하는 방법으로 크게 두 가지 방법으로 나타냈다.

ꊱ String 연산(String Concatenation 연산)을 이용하여 XML 문서를 생성
ꊲ 정보 모델이 제공하는 자기 서술적인 정보를 이용하여 XML 문서에 대한 자동 생성
ꊳ 기타 방법

앞의 두 방법을 나열할 때 혹 독자들은 ‘왜 DOM을 이용하여 XML 문서를 생성하지 않는가?’하고 의문을 가질 수 있다. 물론 내용이 없는 Empty DOM을 생성하여 정보 모델로부터 각 노드의 내용을 생성하고 완전한 DOM이 완성되면 다시 XML 내용을 가진 문자열 스트링으로 생성할 수 있다. 실 세계의 정보를 정보 모델로 구현할 경우 정보 모델은 나름대로 제약 조건을 가지며 데이터의 정합성을 보장 및 체크한다. 정보 모델에서 데이터의 제약 체크가 끝난 후 다시 DOM 객체를 만들어 파싱하는 과정은 시스템에 부하를 가중시키고 비효율적이다. 꼭 필요한 경우가 아니면 굳이 그러한 방법을 사용하지 않아도 된다.

String 연산으로 XML 문서를 생성하기
가장 간단한 방법이며 가장 많이 사용되는 방법이 String 연산으로 XML 문서를 생성하는 방법이다. 단점으로는 각각의 객체에 대해 XML로 만드는 로직을 구현해야 한다는 반복적인 작업으로 데이터 구조가 복잡하고 객체 종류가 많은 경우에는 단순 반복 작업을 많이 해야 한다. <리스트 2>는 앞에서 설명한 Employee 객체와 Dept 객체로부터 Employee XML과 Dept XML을 생성하는 방법을 나타낸다.

<리스트 2> Employee 객체와 Dept XML로부터 문자열 연결 연산으로 XML을 생성하는 방법
// Employee.java
. . .
public String toXML_type1() {
// 화면 출력을 목적으로 CR/LF를 사용
String line = System.getProperty("line.separator");
StringBuffer xml = new StringBuffer();
xml.append("").append(line);
xml.append("").append(EmpNo);
xml.append("
").append(line);
xml.append("").append(EName);
xml.append("
").append(line);
xml.append("").append(Job);
xml.append("
").append(line);
xml.append("").append(Mgr);
xml.append("
").append(line);
xml.append("").append(HireDate);
xml.append("
").append(line);
xml.append("").append(SAL);
xml.append("
").append(line);
xml.append("
").append(line);
return xml.toString();
}
. . .
// Dept.java
public class Dept {
. . .
public String toXML_type1() {
String line = System.getProperty("line.separator");
StringBuffer xml = new StringBuffer();
xml.append("").append(line);
xml.append("").append(DeptNo);
xml.append("
").append(line);
xml.append("").append(DName);
xml.append("
").append(line);
xml.append("").append(Loc);
xml.append("
").append(line);
xml.append("").append(line);
// 구성 Employee들에 대해 Employee의 xml 변환 함수인 toXML_type1()을 호출
for(Enumeration enumeration=Employees.elements();
enumeration.hasMoreElements();) {
Employee employee = (Employee)enumeration.nextElement();
xml.append(employee.toXML_type1());
}
xml.append("").append(line);
xml.append("
").append(line);
return xml.toString();
}
. . .
}

자바 리플렉션 방법을 이용하여 XML 문서를 생성하기
자바의 리플렉션 관련된 패키지들은 클래스 정보의 구조 및 내용을 동적으로 파악하고 정보를 획득하기에 뛰어나다.
<리스트 3>은 필드 구성이 java.lang.String 타입과 java.util.Hashtable 타입으로 구성된 클래스의 객체에 대해 내부 구조를 파악하여 자동으로 XML 문서를 생성하는 함수이다. 이 함수를 확장하여 더 많은 데이터 타입을 지원하도록 할 수 있다. XML을 생성하는 방법은 다음과 같다.

ꊱ Class 타입인 경우 : Employee 클래스는 다음과 같이 변환된다.

<Employee></Employee>

ꊲ java.lang.String 타입인 경우 : String EName=“HongKilDong”과 같은 필드 정보는 다음과 같이 변환된다.

<EName>HongKilDong</EName>

ꊳ java.util.Hashtable 타입의 경우 : Hashtable Employees의 경우는 다음과 같이 변환된다. Hashtable인 Employees 객체는 엘리먼트로 구성되고 Employee 객체들은 의 하위 자식 엘리먼트로 변환된다.

<Employees>

<Employee>

<EmpNo>10</EmpNo>



</Employee>

<Employee></Employee>

</Employees>

<리스트 3> 자바 리플렉션 방법을 이용하여 객체를 XML로 구성하는 방법
. . .
public class XMLUtil {
. . .
public static String toXML(Object obj)
throws Exception{
String line = System.getProperty("line.separator");
StringBuffer xml = new StringBuffer();

// Class 객체를 이용하여 클래스 이름 및 구성 요소를 파악한다.
Class cls = obj.getClass();
String className = cls.getName();

//시작 태그는 클래스명
xml.append("<").append(className).append(">").append(line);

// 필드 정보를 이용하여 객체의 필드 이름 및 값 등을 쉽게 접근한다.
java.lang.reflect.Field fields[] = cls.getFields();
// 모든 필드에 대해 필드 이름을 노드 명으로, 필드 값을 노드 값으로
// 가지는 XML 노드를 생성한다.
for(int i=0;i // 필드 타입이 String인 경우와 Hashtable인 경우만 본문에서는 지원
if(fields[i].getType().getName().equals("java.lang.String"))
{
xml.append("<").append(fields[i].getName()).append(">");
xml.append((String)fields[i].get(obj));
xml.append("");
xml.append(line);
// 필드 타입이 Hashtable인 경우
}else if(fields[i].getType().getName().equals("java.util.Hashtable")){
xml.append("<").append(fields[i].getName()).append(">");
for(Enumeration enumeration=
((Hashtable)fields[i].get(obj)).elements();enumeration.hasMoreElements();)
{
Object ele = enumeration.nextElement();
xml.append(toXML(ele)); // 구성 Employee 엘리먼트에 대해 변환 함수 재귀 호출
}
xml.append("");
}
}
xml.append("").append(line); // 끝 태그
return xml.toString();
}
. . .
public static void main(String args[]) throws Exception{
Hashtable employees = new Hashtable();
// 3개의 Employee 객체를 가진 Dept를 생성하고 객체에서 XML로 변환하는 함수 호출
employees.put("10",new Employee("10","홍길동","편집부","10","2003-01-01","2000"));
employees.put("20",new Employee("20","김철수","편집부","10","2003-03-01","2000"));
employees.put("40",new Employee("40","이영희","편집부","10","2002-03-01","2000"));

Dept dept = new Dept("100","편집부","서울",employees);
System.out.println(XMLUtil.toXML(dept));
}
}

정보 모델의 자기 서술적인 기능을 이용하여 <리스트 3>과 같이 XML 데이터 변환 기능을 구현한 경우에 정보 모델 전체의 클래스의 수가 많고 복잡한 경우에도 유용하게 사용할 수 있다.

맺으면서
이번 호에서는 XML을 저장할 경우에 애플리케이션의 용도에 맞는 저장장치를 선택하는 방법에 대해 살펴봤다. 파일 시스템을 저장 매체로 사용하고 파일로부터 읽은 정보를 시스템 메모리로 로딩하여 쉽게 접근하고 변경한 후 다시 파일 시스템으로 저장하는 방법에 대해 주로 설명했다. 다음에는 데이터베이스 시스템에 XML을 저장하는 방법 및 유형들에 대해 설명할 것이다.

+ Recent posts