package nlib.restful.service; import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import nlib.util.StringUtil; public class XmlConverter { private static final Logger log = LoggerFactory.getLogger(XmlConverter.class); public static HashMap convert(String xmlStr, String rootEleName) throws Exception { if(xmlStr == null) return null; ByteArrayInputStream bIn = new ByteArrayInputStream(xmlStr.getBytes()); HashMap resMap = new HashMap(); try { XMLInputFactory inputFactory = XMLInputFactory.newInstance(); XMLEventReader eventReader = inputFactory.createXMLEventReader(bIn); resMap = getElementValue(rootEleName, eventReader, null); //log.debug("Converting XML to HashMap : Done >> " + resMap); } catch (XMLStreamException e) { log.error("convert XMLStreamException : " + e.toString()); } catch (Exception e) { log.error("convert Error : " + e.toString()); } return resMap; } /** * @param rootElementName * @param eventReader * @param alreadyRootOpened : 부모 요소 찾기 없이 작업 진행할지 여부. false인 경우, rootElementName 요소를 찾아서 이후 값 추출 수행 * @param startElement * @return * @throws Exception */ public static HashMap getElementValue( String rootElementName , XMLEventReader eventReader , XMLEvent firstChildElement) throws Exception { HashMap retMap = new HashMap(); try { int depth = (firstChildElement == null ? 0 : 1); StartElement startElement = null; XMLEvent event = firstChildElement; String upperElementName = null; String elementName = null; //(firstChildElement == null ? null : firstChildElement.asStartElement().getName().getLocalPart()); String content = null; String elementValue = ""; HashMap elementValues = null; boolean hasSubElements = false; boolean isFirst = true; while (eventReader.hasNext()) { // 이벤트가 함께 매개변수로 넘어온 경우, 처음 읽기 생략 if(!isFirst || event == null) { event = eventReader.nextEvent(); } if(isFirst) isFirst = false; // 1 레벨 엘리먼트 찾기 if (depth == 0 && event.isStartElement() && event.asStartElement().getName().getLocalPart().equals(rootElementName)) { depth++; continue; } // 1 레벨 엘리먼트내의 2 레벨 엘리먼트 찾기 if(depth == 1 && elementName == null && event.isStartElement()) { elementName = event.asStartElement().getName().getLocalPart(); elementValue = ""; elementValues = null; hasSubElements = false; depth++; continue; } // 2 레벨 엘리먼트 내용 찾기 if(depth == 2 && elementName != null && event.isCharacters()) { content = event.asCharacters().getData(); if(StringUtil.isNotEmpty(content)) { elementValue += content; } continue; } // 2 레벨 엘리먼트 종료 if(depth == 2 && elementName != null && event.isEndElement()) { if(!elementName.equals(event.asEndElement().getName().getLocalPart())) { throw new Exception("XML문의 요소 시작/종료 태그가 일치하지 않습니다. : " + elementName + " 요소가 " + event.asEndElement().getName().getLocalPart() + "로 종료되었습니다."); } addValue(retMap, elementName, elementValue); //log.debug(elementName + " : -" + elementValue + "_"); elementName = null; elementValue = ""; depth--; } // 2 레벨 엘리먼트 > 하위 엘리먼트 존재하는 경우 if(depth == 2 && elementName != null && event.isStartElement()) { HashMap subMap = getElementValue(elementName, eventReader, event); addValue(retMap, elementName, subMap); depth--; elementName = null; } // 1 레벨 엘리먼트 종료된 경우, 돌아가기 if(depth == 1 && elementName == null && event.isEndElement() && rootElementName.equals(event.asEndElement().getName().getLocalPart())) { depth--; return retMap; } } // while } catch (XMLStreamException e) { log.error("getElementValue Error : " + e.toString()); } catch (Exception e) { log.error("getElementValue Error : " + e.toString()); } return retMap; } public static void addValue(HashMap map, String key, Object value) throws Exception { if(map == null) throw new Exception("값을 넣을 Map 변수가 초기화되지 않았습니다."); if(key == null) return; if(value == null) return; Object curValObj = map.get(key); if(curValObj == null) { map.put(key, value); return; } if(curValObj instanceof String || curValObj instanceof HashMap) { List values = new ArrayList(); values.add(curValObj); values.add(value); map.put(key, values); } else if(curValObj instanceof List) { ((ArrayList)curValObj).add(value); } return; } public static Object convertMapToObject(HashMap map, Class voClass) { final ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); final Object voObj = mapper.convertValue(map, voClass); return voObj; } /* public static void main(String argv[]) throws Exception { XmlConverter xmlConverter = new XmlConverter(); String xmlStr = "\r\n" + "\r\n" + "\r\n" + " S\r\n" + " 성공적으로 조회되었습니다.\r\n" + " 10\r\n" + " 1\r\n" + " 15\r\n" + " \r\n" + " 1\r\n" + " 101\r\n" + " 공지사항 테스트\r\n" + " 15\r\n" + " 2021-07-19\r\n" + " \r\n" + " \r\n" + " 2\r\n" + " 101\r\n" + " 공지사항 테스트\r\n" + " 55\r\n" + " 2021-07-19\r\n" + " \r\n" + " \r\n" + " 3\r\n" + " 101\r\n" + " 공지사항 테스트\r\n" + " 55\r\n" + " 2021-07-19\r\n" + " \r\n" + " \r\n" + " 4\r\n" + " 101\r\n" + " 공지사항 테스트\r\n" + " 55\r\n" + " 2021-07-19\r\n" + " \r\n" + " \r\n" + " 5\r\n" + " 101\r\n" + " 공지사항 테스트\r\n" + " 55\r\n" + " 2021-07-19\r\n" + " \r\n" + " \r\n" + " 6\r\n" + " 101\r\n" + " 공지사항 테스트\r\n" + " 55\r\n" + " 2021-07-19\r\n" + " \r\n" + " 3333\r\n" + ""; HashMap resMap = xmlConverter.convert(xmlStr); } */ }