본문 바로가기
프로그래밍/Java-토이프로젝트

데이터 출력(DB -> json,xml등) 프로그램-3【XML출력】

by 코이킹 2021. 5. 23.
반응형

지난 포스트에 이어서 이 포스트에서는 XML 데이터를 출력하는 기능에 대해 정리하겠습니다. 

1. 실행결과

 

 

2. 구현 방법

 이 토이 프로젝트에서는 특정 테이블의 데이터를 XML로 그대로 옮기는 것 만을 생각했기에

 1) DB 테이블의 데이터를 XML로 옮기는 기능을 구현한 추상 클래스를 만들었고
 2) Item테이블의 정보가 담긴 XML에서 Item객체로 , Item객체에서 Item의 정보가 담긴 XML로 변환하게 해주는 클래스를 1) 추상클래스를 상속하여 만들었습니다. 

 이 토이 프로젝트에서는 파싱에 관련된 기능은 없지만 
구상하고 있는 토이프로젝트 중 대용량의 XML 파싱 기능이 필요한 경우가 있으므로 겸사겸사 SAX방식으로 XML를 파싱 하는 기능도 만들어 두었습니다.

 

※ 아래의 코드가 XML을 다루기 위한 추상 XML 유틸 클래스입니다.

package tools.utils;

/**
 * XML 데이터를 지정한 클래스(데이터를 담기위한 클래스) 형식으로 파싱, 
 * 또는  지정한 클래스에 담긴 데이터를 XML형식으로 변환해주는 유틸클래스.
 * 대용량 XML데이터를 처리하는데 있어 유리한 SAXBuilder를 사용했다.
 * 이 코드를 사용하기 위해선 build.gradle에 아래의 의존성을 추가해주어야한다.
 * // https://mvnrepository.com/artifact/org.jdom/jdom
 * compile group: 'org.jdom', name: 'jdom', version: '2.0.2'
 * 
 * @author lee-y
 *
 */
public abstract class XmlUtil {
	
	int count = 0;
	
	/**
	 * xml 데이터를 받아오는 부분 
	 * 
	 * @param target : 파싱 대상 XML
	 * @param obj    : 파싱한 데이터를 담기위한 클래스
	 * @return
	 */
	public Object parser(String target, Object obj) {
		
		SAXBuilder builder = new SAXBuilder();
		InputStream xmlInput = new ByteArrayInputStream(target.getBytes());
		
		Document doc;
		Element el;
		try {
			doc = builder.build(xmlInput, "UTF-8");
			el = doc.getRootElement();
			getObject(el, obj);
			
		} catch (JDOMException e) { e.printStackTrace();
		} catch (IOException e) { e.printStackTrace(); 
		} catch (Exception e) { e.printStackTrace(); }
		 
		return obj;
	}
	
	/**
	 * XML데이터를 파싱하기 위한 메소드.
	 * 재귀적인 방식으로 동작하도록 설계함.
	 * 
	 * @param el  : String 형식의 XML데이터를 Element형식으로 변환한것.
	 * @param obj : 파싱한 데이터를 담기위한 클래스
	 */
	public void getObject(Element el, Object obj) {
		
		count++;
		int countInFirstRoop = 0;
		List<?> childList = el.getChildren();
		Iterator<?> childItr = childList.iterator();
		
		while(childItr.hasNext()) {
			countInFirstRoop++;
			Element childEl = (Element)childItr.next();
			String elName = new String(childEl.getName());
			List<?> grandChildList = childEl.getChildren();
			Iterator<?> grandChildItr = grandChildList.iterator();
			
			if (grandChildItr.hasNext()) {
				System.out.println("("+count+") ("+countInFirstRoop+") [ "+ elName + " ] has child");
				getObject(childEl, obj);
				
			} else {
				List<?> contentList = childEl.getContent();
				Iterator<?> contentItr = contentList.iterator();
				
				if (contentItr.hasNext()) {
					Content content = (Content) contentItr.next();
					System.out.println("("+count+") ("+countInFirstRoop+") "+ elName + " : " + content.getValue());
					
					if (!setData(elName, content.getValue(), obj)) {
						System.err.println("Error ["+ elName+"], ["+content.getValue()+"]");
					}
					
				} else {
					System.out.println("("+count+") ("+countInFirstRoop+") "+elName + " : Null value");
				}
			}
			
		}
	}
	
	/**
	 * XML데이터를 파싱해서 데이터 클래스에 데이터를 담는 메소드.
	 * 
	 * @param elName : XML태그명
	 * @param val    : XML태그의 값
	 * @param model  : 파싱한 데이터를 담기위한 클래스
	 * @return
	 */
	public abstract boolean setData(String elName, String val, Object obj);
	
	
	/**
	 * 지정한 데이터 클래스에 담긴 데이터를 XML형식으로 변환해주는 기능.
	 * 
	 * @param obj  : XML로 변환하기 위한 데이터 클래스
	 * @return
	 */
	public abstract String makeXml(Object obj);
	
	
}


※ 아래의 코드가 추상 클래스를 상속한 Item만을 다루기 위한 XML 유틸 클래스입니다. 

package tools.utils;

public class ItemXmlUtil extends XmlUtil {
	
	/**
	 * XML데이터를 파싱해서 데이터 클래스에 데이터를 담는 메소드.
	 * 
	 * @param elName : XML태그명
	 * @param val    : XML태그의 값
	 * @param model  : 파싱한 데이터를 담기위한 클래스
	 * @return
	 */
	@Override
	public boolean setData(String elName, String val, Object obj) {
		if (val == null) return false;
		
		System.out.println("Element Name : ["+elName+"], Value : ["+val+"]");
		
		// ----- Start 이 부분은 지정한 데이터 클래스에 맞게 재정의를 해줘야함. -----
		Item model = (Item) obj;
		
		if (elName.equals("itemId")) {
			model.setItemId(Integer.parseInt(val));
			
		} else if (elName.equals("itemName")) {
			model.setItemName(val);
			
		} else if (elName.equals("itemDescription")) {
			model.setItemDescription(val);
			
		} else if (elName.equals("makerCode")) {
			model.setMakerCode(val);
			
		} else if (elName.equals("price")) {
			model.setPrice(Integer.parseInt(val));

		} else if (elName.equals("saleStatus")) {
			model.setSaleStatus(Integer.parseInt(val));
		
		} else if (elName.equals("images")) {
			model.getImages().add(val);
			
	    } else {
			return false;
		}
		
		return true;
	}
	
	/**
	 * 지정한 데이터 클래스에 담긴 데이터를 XML형식으로 변환해주는 기능.
	 * 
	 * @param obj  : XML로 변환하기 위한 데이터 클래스
	 * @return
	 */
	@Override
	public String makeXml(Object obj) {
		if (obj == null) return "";
		Item i = (Item)obj;
		
		Element rootEl = new Element("item");
		Document doc = new Document(rootEl);

		doc.getRootElement().addContent(new Element("itemId").addContent(String.valueOf(i.getItemId())));
		doc.getRootElement().addContent(new Element("itemName").addContent(i.getItemName()));
		doc.getRootElement().addContent(new Element("itemDescription").addContent(i.getItemDescription()));
		doc.getRootElement().addContent(new Element("makerCode").addContent(i.getMakerCode()));
		doc.getRootElement().addContent(new Element("price").addContent(String.valueOf(i.getPrice())));
		doc.getRootElement().addContent(new Element("saleStatus").addContent(String.valueOf(i.getSaleStatus())));
		Element images = new Element("images");
		
		for (String img : i.getImages()) {
			images.addContent(new Element("image").addContent(img));
		}

		doc.getRootElement().addContent(images);
		
		Format fm = Format.getPrettyFormat();
		fm.setEncoding("UTF-8");
		XMLOutputter output = new XMLOutputter(fm);
		return output.outputString(doc);
		
	}
	
	
	/**
	 * 지정한 데이터 클래스에 담긴 데이터를 XML형식으로 변환해주는 기능.
	 * 
	 * @param list : XML로 변환하기 위한 데이터 클래스의 리스트
	 * @return
	 */
	public String makeXmlList(List<Item> list) {
		if (list == null) return "";
		
		
		Element rootEl = new Element("items");
		Document doc = new Document(rootEl);
		
		for (Item i : list) {
			Element item = new Element("item");
			item.addContent(new Element("itemId").addContent(String.valueOf(i.getItemId())));
			item.addContent(new Element("itemName").addContent(i.getItemName()));
			item.addContent(new Element("itemDescription").addContent(i.getItemDescription()));
			item.addContent(new Element("makerCode").addContent(i.getMakerCode()));
			item.addContent(new Element("price").addContent(String.valueOf(i.getPrice())));
			item.addContent(new Element("saleStatus").addContent(String.valueOf(i.getSaleStatus())));
			Element images = new Element("images");
			
			for (String img : i.getImages()) {
				images.addContent(new Element("image").addContent(img));
			}
			
			item.addContent(images);
			
			doc.getRootElement().addContent(item);
		}
		
		Format fm = Format.getPrettyFormat();
		fm.setEncoding("UTF-8");
		XMLOutputter output = new XMLOutputter(fm);
		return output.outputString(doc);
		
	}
	
}

※ 위의 유틸 클래스의 메서드를 ItemDataOutputXml.java에서 사용하여 Item객체를 XML 데이터로 변환하여 파일로 출력합니다.

package tools.dataoutput;

import tools.models.Item;
import tools.utils.ItemXmlUtil;

public class ItemDataOutputXml extends ItemDataOutput {

	private ItemXmlUtil xmlUtil = new ItemXmlUtil();
	
	public ItemDataOutputXml() {
		super();
		
		Properties prop = new Properties();
		InputStream is = null;
		try {
			is = ItemDataOutput.class.getClassLoader().getResourceAsStream("config.dataoutput.properties");
			prop.load(is);
			super.OUTPUT_DIR = prop.getProperty("output.dir.dataoutput.xml");
			super.OUTPUT_FILE_NAME = prop.getProperty("output.filename.dataoutput.xml");
			super.EXTENTION = ".xml";
			super.ENCODING_TYPE = prop.getProperty("encodingtype.dataoutput.xml");
			
		} catch (Exception e) {
			System.out.println("Properties load fail!!");
		}
	}

	@Override
	public void outputDataToFile(List<Item> list, int processNum) {
		String outputFilePath = makeFileName(processNum);
		
		try (BufferedWriter bw = Files.newBufferedWriter(
				Paths.get(outputFilePath), 
				Charset.forName(ENCODING_TYPE),
				StandardOpenOption.CREATE_NEW)) {

			bw.write(xmlUtil.makeXmlList(list));
		
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NullPointerException e) {
			e.printStackTrace();
		}
		
	}


}
반응형

댓글