package org.araqne.logdb.impl;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class XmlParser {
private XmlParser() {
}
@SuppressWarnings("unchecked")
public static Map<String, Object> parseXml(String xml) throws Throwable {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xml)));
doc.getDocumentElement().normalize();
Node rootNode = doc.getLastChild();
return (Map<String, Object>) parseNode(rootNode);
}
@SuppressWarnings("unchecked")
public static Object parseNode(Node node) {
NodeList list = node.getChildNodes();
NamedNodeMap attrs = node.getAttributes();
int childCount = list.getLength();
int attrCount = attrs != null ? attrs.getLength() : 0;
if (childCount == 0 && attrCount == 0) {
String text = node.getTextContent().trim();
if (text.isEmpty())
return null;
return text;
} else if (childCount == 1 && attrCount == 0 && isTextNode(list.item(0))) {
String text = list.item(0).getTextContent().trim();
if (text.isEmpty())
return null;
return text;
}
Map<String, Object> m = new HashMap<String, Object>();
for (int i = 0; i < attrCount; i++) {
Node attr = attrs.item(i);
if (getNodeName(attr).equals("xmlns"))
continue;
m.put(getNodeName(attr), attr.getTextContent().trim());
}
for (int i = 0; i < childCount; i++) {
Node child = list.item(i);
Object content = parseNode(child);
if (content == null)
continue;
Object v = m.get(getNodeName(child));
List<Object> children = null;
if (v instanceof List) {
children = (List<Object>) v;
} else {
children = new ArrayList<Object>();
if (v != null)
children.add(v);
m.put(getNodeName(child), children);
}
children.add(content);
}
for (String key : m.keySet()) {
Object val = m.get(key);
if (!(val instanceof List))
continue;
List<Object> l = (List<Object>) val;
if (l != null && l.isEmpty())
m.put(key, null);
// TODO: add formal option
if (l.size() == 1)
m.put(key, l.get(0));
}
if (m.isEmpty())
return null;
return m;
}
private static String getNodeName(Node node) {
if (isTextNode(node))
return "_text";
return node.getNodeName();
}
private static boolean isTextNode(Node node) {
short nodeType = node.getNodeType();
return nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE;
}
}