package com.elsea.stone.property; import java.io.File; import javax.xml.parsers.*; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * PropertyPoolReader * * Reads in Stone-formatted XML data and returns it to its original * Property Pool state. The resulting Property Pool is stored as a * member of the Property Pool Reader object and can be accessed via * the accessor method getPropertyPool. * * @author Connor M. Elsea */ public class PropertyPoolReader { private PropertyPool result; /** * Reads in Stone-formatted XML data and returns it to its original * Property Pool state. The resulting Property Pool is stored as a * member of the Property Pool Reader object and can be accessed via * the accessor method getPropertyPool. * * @param file The file to read in from. Should be an XML file. * @return Whether or not the operating was successful. Minor, non-file, errors * still will return true. Look at console warnings for more detailed * failure alerts for minor issues such as formatting or altered data. */ public boolean read(File file) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(file); doc.getDocumentElement().normalize(); NodeList list = doc.getChildNodes(); result = new PropertyPool(); // Parse, setting parent as the first node parse(result, list.item(0)); return true; } catch (Exception ex) { ex.printStackTrace(); return false; } } /** * A recursive method that loops through the Document's nodes and builds * a Property Pool from them. * * @param pool The resulting pool * @param parent The parent object to pass down the recursive calls */ private void parse(PropertyPool pool, Node parent) { if (parent.hasChildNodes()) { NodeList list = parent.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { Node current = list.item(i); // Some elements may be random text nodes, so we must only use the nodes // that are important to our data. if (current.getNodeType() == Node.ELEMENT_NODE) { // Check group attribute, determine if node is a group Node attr = current.getAttributes().item(0); boolean group = attr.getNodeName().equals("group") && attr.getNodeValue().equals("true"); // Check type attribute, determine type of node Node typeAttr = current.getAttributes().item(1); String type = typeAttr.getNodeValue(); // If the current node should be a PropertyGroup if (group) { pool.group(current.getNodeName()); if (type != null) pool.type(type); else pool.type(""); parse(pool, current); pool.end(); } // If the current node should be a PropertyElement else { NodeList propertyChildren = current.getChildNodes(); Node defaultNode = null; Node currentNode = null; String nodeName = current.getNodeName(); String defaultValue = null; String currentValue = null; // Some children will be text nodes, etc So we loop through all // of them and find the ones that are not, which, in a properly // formatted document, will mean that they are the nodes for // default and current. for (int c = 0; c < propertyChildren.getLength(); c++) { Node child = propertyChildren.item(c); if (child.getNodeType() == Node.ELEMENT_NODE) { if (child.getNodeName().equals("default")) defaultNode = child; else if (child.getNodeName().equals("current")) currentNode = child; } } if (defaultNode != null) defaultValue = defaultNode.getChildNodes().item(0).getNodeValue(); if (currentNode != null) currentValue = currentNode.getChildNodes().item(0).getNodeValue(); pool.property(nodeName, defaultValue, currentValue); if (type != null) pool.type(type); } } } } } public PropertyPool getPropertyPool() { return result; } }