package com.framsticks.parsers; import java.io.InputStream; import java.util.LinkedList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.framsticks.params.AccessInterface; import com.framsticks.params.Registry; import com.framsticks.util.AutoBuilder; import com.framsticks.util.FramsticksException; import com.framsticks.util.lang.Strings; public class XmlLoader { private static final Logger log = Logger.getLogger(XmlLoader.class); protected Registry registry = new Registry(); /** * */ public XmlLoader() { } /** * @return the registry */ public Registry getRegistry() { return registry; } boolean useLowerCase = false; /** * @param useLowerCase the useLowerCase to set */ public void setUseLowerCase(boolean useLowerCase) { this.useLowerCase = useLowerCase; } public String mangleName(String name) { return useLowerCase ? name.toLowerCase() : name; } public String mangleAttribute(String name) { return useLowerCase ? name.toLowerCase() : Strings.uncapitalize(name); } public Object processElement(Element element) { final String name = mangleName(element.getNodeName()); if (name.equals("import")) { String className = element.getAttribute("class"); try { registry.registerAndBuild(Class.forName(className)); return null; } catch (ClassNotFoundException e) { throw new FramsticksException().msg("failed to import class").arg("name", name).cause(e); } } AccessInterface access = registry.createAccess(name); Object object = access.createAccessee(); assert object != null; access.select(object); NamedNodeMap attributes = element.getAttributes(); for (int i = 0; i < attributes.getLength(); ++i) { Node attributeNode = attributes.item(i); access.set(mangleAttribute(attributeNode.getNodeName()), attributeNode.getNodeValue()); } NodeList children = element.getChildNodes(); log.debug("found " + children.getLength() + " children in " + object); for (int i = 0; i < children.getLength(); ++i) { Node childNode = children.item(i); if (!(childNode instanceof Element)) { continue; } Object childObject = processElement((Element) childNode); if (childObject == null) { continue; } List childrenObjects = new LinkedList<>(); if (childObject instanceof AutoBuilder) { childrenObjects.addAll(((AutoBuilder) childObject).autoFinish()); } else { childrenObjects.add(childObject); } for (Object child : childrenObjects) { access.tryAutoAppend(child); } } log.debug("loaded " + object); return object; } public Object load(InputStream stream) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder db = factory.newDocumentBuilder(); Document document = db.parse(stream); document.getDocumentElement().normalize(); Element element = document.getDocumentElement(); assert element != null; return processElement(element); } catch (Exception e) { throw new FramsticksException().msg("failed to load").cause(e); } } public T load(Class type, InputStream stream) { registry.registerAndBuild(type); Object object = load(stream); if (type.isAssignableFrom(object.getClass())) { return type.cast(object); } throw new FramsticksException().msg("invalid type has been loaded"); } }