001package test;
002
003import java.io.IOException;
004import java.io.StringReader;
005import java.util.ArrayList;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009
010import javax.xml.parsers.DocumentBuilder;
011import javax.xml.parsers.DocumentBuilderFactory;
012
013import org.w3c.dom.Document;
014import org.w3c.dom.Element;
015import org.w3c.dom.Node;
016import org.w3c.dom.NodeList;
017import org.w3c.dom.Attr;
018import org.xml.sax.InputSource;
019
020public class XmlParser {
021
022    private String xml;
023    private String rootName;
024    private Map<String, Object> root;
025
026    public XmlParser(String xml) throws Exception {
027        super();
028        this.xml = xml;
029        root = xml2Map(this.xml);
030    }
031    
032    public void put(String name, Map<String, Object> map) {
033        root.put(getShortName(name), map);
034    }
035    
036    public String getRootName() {
037        return rootName;
038    }
039
040    public Object get(String... keys) {
041        Object o = null;
042        if (root == null)
043            return null;
044
045        Map<String, Object> m = (Map<String, Object>) root;
046        for (int i = 0; i < keys.length; i++) {
047            o = m.get(keys[i]);
048            if (o == null) {
049                break;
050            } else {
051                if (o instanceof Map) {
052                    m = (Map<String, Object>) o;
053                    continue;
054                } else {
055                    if (i != keys.length - 1)
056                        o = null;
057                }
058            }
059        }
060        if (o != null && o instanceof String) {
061            return ((String) o).trim();
062        }
063        return o;
064    }
065    
066    public List<Object> getList(String... keys) {
067        List<Object> list = new ArrayList<Object>();
068        Object o = null;
069        if (root == null)
070            return null;
071
072        Map<String, Object> m = (Map<String, Object>) root;
073        for (int i = 0; i < keys.length; i++) {
074            o = m.get(keys[i]);
075            if (o == null) {
076                break;
077            } else {
078                if (o instanceof Map) {
079                    m = (Map<String, Object>) o;
080                    continue;
081                } else {
082                    if (i != keys.length - 1)
083                        o = null;
084                }
085            }
086        }
087        if (o != null) {
088            if (o instanceof String) {
089                o = ((String) o).trim();
090                list.add(o);
091            }
092            if (o instanceof List) {
093                list.addAll((List) o);
094            } else {
095                list.add(o);
096            }
097        }
098        return list;
099    }
100
101    public Object path(String paths) {
102        if (paths == null) return null;
103        return get(paths.trim().split("\\."));
104    }
105    
106    public List<Object> pathList(String paths) {
107        if (paths == null) return null;
108        return getList(paths.trim().split("\\."));
109    }    
110
111    public Map<String, Object> xml2Map(String xml) throws Exception {
112        Map<String, Object> map = new HashMap<>();
113        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
114        factory.setNamespaceAware(false);
115        factory.setValidating(false);
116        
117        DocumentBuilder builder = factory.newDocumentBuilder();
118        Document document = builder.parse(new InputSource(new StringReader(xml)));
119        
120        Element rootElement = document.getDocumentElement();
121        rootName = rootElement.getNodeName();
122        
123        NodeList childNodes = rootElement.getChildNodes();
124        for (int i = 0; i < childNodes.getLength(); i++) {
125            Node node = childNodes.item(i);
126            if (node.getNodeType() == Node.ELEMENT_NODE) {
127                Element element = (Element) node;
128                processElement(element, map);
129            }
130        }
131        return map;
132    }
133
134    private void processElement(Element element, Map<String, Object> parentMap) {
135        String elementName = element.getNodeName();
136        NodeList children = element.getChildNodes();
137        
138        boolean hasElementChildren = false;
139        for (int i = 0; i < children.getLength(); i++) {
140            if (children.item(i).getNodeType() == Node.ELEMENT_NODE) {
141                hasElementChildren = true;
142                break;
143            }
144        }
145        
146        if (!hasElementChildren) {
147            String textContent = getElementText(element);
148            handleValue(parentMap, elementName, textContent, element);
149        } else {
150            Map<String, Object> childMap = new HashMap<>();
151            for (int i = 0; i < children.getLength(); i++) {
152                Node child = children.item(i);
153                if (child.getNodeType() == Node.ELEMENT_NODE) {
154                    processElement((Element) child, childMap);
155                }
156            }
157            
158            if (childMap.isEmpty()) {
159                String textContent = getElementText(element);
160                handleValue(parentMap, elementName, textContent, element);
161            } else {
162                handleMap(parentMap, elementName, childMap, element);
163            }
164        }
165    }
166
167    private void handleValue(Map<String, Object> map, String key, Object value, Element element) {
168        Object existingValue = map.get(key);
169        
170        if (existingValue == null) {
171            map.put(getShortName(key), blank(value));
172            map.put("@" + getShortName(key), parseAttributes(element));
173        } else if (existingValue instanceof List) {
174            ((List<Object>) existingValue).add(blank(value));
175            
176            Object existingAttrs = map.get("@" + getShortName(key));
177            if (existingAttrs instanceof List) {
178                ((List<Object>) existingAttrs).add(parseAttributes(element));
179            }
180        } else {
181            List<Object> valueList = new ArrayList<>();
182            valueList.add(existingValue);
183            valueList.add(blank(value));
184            map.put(getShortName(key), valueList);
185            
186            List<Object> attrList = new ArrayList<>();
187            attrList.add(map.get("@" + getShortName(key)));
188            attrList.add(parseAttributes(element));
189            map.put("@" + getShortName(key), attrList);
190        }
191    }
192
193    private void handleMap(Map<String, Object> map, String key, Map<String, Object> value, Element element) {
194        Object existingValue = map.get(key);
195        
196        if (existingValue == null) {
197            map.put(getShortName(key), value);
198            map.put("@" + getShortName(key), parseAttributes(element));
199        } else if (existingValue instanceof List) {
200            ((List<Object>) existingValue).add(value);
201            
202            Object existingAttrs = map.get("@" + getShortName(key));
203            if (existingAttrs instanceof List) {
204                ((List<Object>) existingAttrs).add(parseAttributes(element));
205            }
206        } else {
207            List<Object> valueList = new ArrayList<>();
208            valueList.add(existingValue);
209            valueList.add(value);
210            map.put(getShortName(key), valueList);
211            
212            List<Object> attrList = new ArrayList<>();
213            attrList.add(map.get("@" + getShortName(key)));
214            attrList.add(parseAttributes(element));
215            map.put("@" + getShortName(key), attrList);
216        }
217    }
218
219    public static Map<String, String> parseAttributes(Element element) {
220        Map<String, String> atts = new HashMap<>();
221        if (element.hasAttributes()) {
222            for (int i = 0; i < element.getAttributes().getLength(); i++) {
223                Attr attr = (Attr) element.getAttributes().item(i);
224                atts.put(attr.getName(), attr.getValue());
225            }
226        }
227        return atts;
228    }
229    
230    private String getElementText(Element element) {
231        StringBuilder text = new StringBuilder();
232        NodeList childNodes = element.getChildNodes();
233        
234        for (int i = 0; i < childNodes.getLength(); i++) {
235            Node node = childNodes.item(i);
236            if (node.getNodeType() == Node.TEXT_NODE) {
237                text.append(node.getNodeValue());
238            }
239        }
240        
241        return text.toString();
242    }
243    
244    public Map<String, Object> getRoot() {
245        return root;
246    }
247
248    private static Object blank(Object value) {
249        return (value == null || value.toString().trim().equals("")) ? null : value;
250    }
251    
252    protected static String join(List<String> list, String conjunction) {
253        StringBuilder sb = new StringBuilder();
254        boolean first = true;
255        for (String item : list) {
256            if (first)
257                first = false;
258            else
259                sb.append(conjunction);
260            
261            sb.append(item.trim());
262        }
263        return sb.toString();
264    }
265    
266    private String getShortName(String nodeName) {
267        return nodeName.replaceFirst("^.*:","");
268    }    
269    
270}
271