package org.korsakow.ide.util; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.validation.SchemaFactory; import org.apache.log4j.Logger; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.korsakow.services.finder.ListNodeList; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class DomUtil { /** * Hack until i whip up a schema/dtd * @param node * @param id * @return */ public static Element getElementById(Node node, String id) { if (node.getNodeType() == Node.ELEMENT_NODE) { Element elm = (Element)node; if (elm.hasAttribute("id") && elm.getAttribute("id").equals(id)) return elm; } NodeList childNodes = node.getChildNodes(); int length = childNodes.getLength(); for (int i = 0; i < length; ++i) { if (childNodes.item(i).getNodeType() != Node.ELEMENT_NODE) continue; Element child = (Element)childNodes.item(i); child = getElementById(child, id); if (child != null) return child; } return null; } public static Document parseXMLString(String xmltext) throws SAXException, ParserConfigurationException, IOException { return parseXML( new ByteArrayInputStream( xmltext.getBytes( "UTF-8" ) ) ); } public static Document parseXMLFile(String filename) throws SAXException, ParserConfigurationException, IOException { return parseXML(new File(filename)); } public static Document parseXML(File file) throws SAXException, ParserConfigurationException, IOException { return parseXML(new FileInputStream(file)); } public static Document parseXML(InputStream input) throws SAXException, ParserConfigurationException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(false); factory.setValidating(false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); DocumentBuilder docBuilder = factory.newDocumentBuilder(); Document doc = docBuilder.parse(input); return doc; } public static Document createDocument() throws ParserConfigurationException, SAXException { SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); // dbfac.setSchema(schemaFactory.newSchema()); DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); Document doc = docBuilder.newDocument(); return doc; } public static Transformer createTransformer() throws TransformerException { TransformerFactory factory = TransformerFactory.newInstance(); // factory.setAttribute("indent-number", 4); Transformer xformer = factory.newTransformer(); xformer.setOutputProperty(OutputKeys.INDENT, "yes"); xformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); xformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); xformer.setOutputProperty(OutputKeys.METHOD, "xml"); xformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml"); return xformer; } public static String toXMLString(Node node) throws TransformerException, IOException { Transformer xformer = createTransformer(); //create string from xml tree StringWriter sw = new StringWriter(); StreamResult result = new StreamResult(sw); DOMSource source = new DOMSource(node); xformer.transform(source, result); sw.close(); return sw.toString(); } public static void writeDomXML(Document doc, File file) throws TransformerException, IOException { if (file == null) throw new NullPointerException(); File parentFile = file.getParentFile(); if (parentFile != null) file.getParentFile().mkdirs(); writeDomXML(doc, new FileOutputStream(file)); } public static void writeDomXML(Document doc, OutputStream output) throws TransformerException, IOException { // ug, the transformer stuff is broken under OSX for java 1.5, as far as pretty printing xml goes XMLSerializer serializer = new XMLSerializer(output, new OutputFormat("xml", "UTF-8", true)); serializer.serialize(doc); // Transformer xformer = createTransformer(doc); // StreamResult result = new StreamResult(output); // DOMSource source = new DOMSource(doc); // xformer.transform(source, result); output.close(); } public static Element findChildByTagName(Element parent, String tagName) { NodeList childNodes = parent.getChildNodes(); int length = childNodes.getLength(); for (int i = 0; i < length; ++i) { Node child = childNodes.item(i); if (child instanceof Element == false) continue; if (((Element)child).getTagName().equals(tagName)) return (Element)child; } return null; } public static Element findElementByPath(Document parent, String path) { Element element = parent.getDocumentElement(); String name = element.getTagName(); if (path.length()==0) return null; if (path.charAt(0)!='/' || !path.startsWith(name, 1)) return null; if (path.length() < name.length() +2 || path.charAt(name.length()+1)!='/') return null; path = path.substring(name.length()+2); return findElementByPath(parent.getDocumentElement(), path); } public static Element findElementByPath(Element parent, String path) { String[] bits = path.split("/"); for (int i = 0; i < bits.length; ++i) { Element child = findChildByTagName(parent, bits[i]); if (child == null) return null; parent = child; } return parent; } public static NodeList getChildElements(Element parent) { ListNodeList list = new ListNodeList(); NodeList children = parent.getChildNodes(); int length = children.getLength(); for (int i = 0; i < length; ++i) { Node item = children.item(i); if (item instanceof Element) list.add(item); } return list; } public static Collection<Element> findChildrenByTagName(Element parent, String tagName) { Collection<Element> children = new ArrayList<Element>(); NodeList childNodes = parent.getChildNodes(); int length = childNodes.getLength(); for (int i = 0; i < length; ++i) { Node child = childNodes.item(i); if (child instanceof Element == false) continue; if (((Element)child).getTagName().equals(tagName)) children.add((Element)child); } return children; } public static Element findChildByIdTag(Element parent, String tagName, String id) { Collection<Element> children = DomUtil.findChildrenByTagName(parent, tagName); for (Element child : children) { String childId = getString(child, "id"); if (id.equals(childId)) return child; } return null; } public static boolean isEqualAsXMLString(Document a, Document b) { try { String strA = toXMLString(a); String strB = toXMLString(b); return strA.equals(strB); } catch (Exception e) { Logger.getLogger(DomUtil.class).debug(e); return false; } } /** * Gets a value from child node whose sole contents is a text or cdata section * @param elm * @param childName * @return null if not found */ public static String getString(Element elm, String childName) { Element child = findChildByTagName(elm, childName); if (child != null) { NodeList childNodes = child.getChildNodes(); int length = childNodes.getLength(); for (int i = 0; i < length; ++i ) { Node valueNode = childNodes.item(i); switch (valueNode.getNodeType()) { case Node.CDATA_SECTION_NODE: case Node.TEXT_NODE: return valueNode.getNodeValue(); } } return ""; } return null; } public static Element setString(Document doc, Element elm, String childName, String value) { Collection<Element> list = findChildrenByTagName(elm, childName); for (Element child : list) elm.removeChild(child); return appendTextNode(doc, elm, childName, value); } public static Long getLong(Element elm, String childName) { String str = getString(elm, childName); if (str == null) return null; return Long.parseLong(str); } public static Element setLong(Document doc, Element elm, String childName, Long value) { Collection<Element> list = findChildrenByTagName(elm, childName); for (Element child : list) elm.removeChild(child); return appendNumberNode(doc, elm, childName, value); } public static Integer getInt(Element elm, String childName) { String str = getString(elm, childName); if (str == null) return null; return Integer.parseInt(str); } public static void setInt(Document doc, Element elm, String childName, Integer value) { Collection<Element> list = findChildrenByTagName(elm, childName); for (Element child : list) elm.removeChild(child); appendNumberNode(doc, elm, childName, value); } public static Float getFloat(Element elm, String childName) { String str = getString(elm, childName); if (str == null) return null; return Float.parseFloat(str); } public static void setFloat(Document doc, Element elm, String childName, Float value) { Collection<Element> list = findChildrenByTagName(elm, childName); for (Element child : list) elm.removeChild(child); appendNumberNode(doc, elm, childName, value); } public static Boolean getBoolean(Element elm, String childName) { String str = getString(elm, childName); if (str == null) return null; return Boolean.parseBoolean(str); } public static Element setBoolean(Document doc, Element elm, String childName, Boolean value) { Collection<Element> list = findChildrenByTagName(elm, childName); for (Element child : list) elm.removeChild(child); return appendBooleanNode(doc, elm, childName, value); } /** * Creates and appends an element whose textvalue is value * @param elm parent element * @param name name of new child * @param value inner text value */ public static Element appendTextNode(Document doc, Node elm, String name, Object value) { if (value == null) return null; Element valueNode = doc.createElement(name); valueNode.appendChild(doc.createCDATASection(value.toString())); elm.appendChild(valueNode); return valueNode; } public static Element appendNumberNode(Document doc, Node elm, String name, Number value) { return DomUtil.appendNumberNode(doc, elm, name, value, null); } public static Element appendNumberNode(Document doc, Node elm, String name, Number value, Object defaultValue) { return appendTextNode(doc, elm, name, value!=null?value:defaultValue); } public static Element appendBooleanNode(Document doc, Node elm, String name, boolean value) { return appendTextNode(doc, elm, name, value?"true":"false"); } }