package com.googlecode.mycontainer.commons.util; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class XMLQuery { private final List<Node> nodes; public XMLQuery() { nodes = new ArrayList<Node>(); } public XMLQuery(List<Node> nodes) { this(); if (nodes == null) { return; } this.nodes.addAll(nodes); } public XMLQuery(String xml) { XMLQuery query = append(xml); this.nodes = query.nodes; } private DocumentBuilder getDocumentBuilder() { try { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); documentBuilderFactory.setCoalescing(true); return documentBuilderFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } } private XPath getXPath() { return XPathFactory.newInstance().newXPath(); } private Transformer getTransformer() throws TransformerConfigurationException, TransformerFactoryConfigurationError { return TransformerFactory.newInstance().newTransformer(); } public XMLQuery append(String xml) { try { DocumentBuilder builder = getDocumentBuilder(); Document root = builder.parse(new ByteArrayInputStream(xml.getBytes("utf-8"))); return append(root); } catch (FactoryConfigurationError e) { throw new RuntimeException(e); } catch (SAXException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } private XMLQuery append(Node node) { XMLQuery ret = new XMLQuery(); ret.nodes.add(node); return ret; } @Override public String toString() { return "" + nodes; } public String toXML() { try { Transformer t = getTransformer(); t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); StringWriter sw = new StringWriter(); StreamResult result = new StreamResult(sw); for (Node node : this.nodes) { t.transform(new DOMSource(node), result); } return sw.toString(); } catch (TransformerConfigurationException e) { throw new RuntimeException(e); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (TransformerFactoryConfigurationError e) { throw new RuntimeException(e); } catch (TransformerException e) { throw new RuntimeException(e); } } public XMLQuery clone() { return new XMLQuery(this.nodes); } public XMLQuery find(String query) { try { XPath xpath = getXPath(); XPathExpression expr = xpath.compile(query); XMLQuery ret = new XMLQuery(); for (Node node : this.nodes) { NodeList result = (NodeList) expr.evaluate(node, XPathConstants.NODESET); convertNodeList(result, ret.nodes); } return ret; } catch (XPathExpressionException e) { throw new RuntimeException(e); } } private List<Node> convertNodeList(NodeList result, List<Node> nodes) { if (nodes == null) { nodes = new ArrayList<Node>(); } for (int i = 0; i < result.getLength(); i++) { Node node = result.item(i); nodes.add(node); } return nodes; } public String text() { StringBuilder sb = new StringBuilder(); for (Node node : this.nodes) { if (node.getNodeType() == Node.ATTRIBUTE_NODE || node.getNodeType() == Node.TEXT_NODE) { sb.append(' ').append(node.getNodeValue()); } } if (sb.length() == 0) { return null; } sb.deleteCharAt(0); return sb.toString(); } public int size() { return nodes.size(); } // REFACT! public XMLQuery item(int i) { return get(i); } public XMLQuery get(int i) { XMLQuery ret = new XMLQuery(); ret.nodes.add(nodes.get(i)); return ret; } public String getContent() { if (nodes.isEmpty()) { return null; } Node node = nodes.get(0); String ret = node.getNodeValue(); return (ret == null ? null : ret.trim()); } public String getContent(String parent) { if (nodes.isEmpty()) { return null; } for (Node node : nodes) { if (node.getParentNode().getNodeName().equals(parent)) { return node.getNodeValue(); } } return null; } public static XMLQuery create(List<Node> nodes) { XMLQuery ret = new XMLQuery(); ret.nodes.addAll(nodes); return ret; } public static XMLQuery parse(byte[] xml, boolean ns) { try { XMLQuery ret = new XMLQuery(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(ns); factory.setCoalescing(true); DocumentBuilder builder = factory.newDocumentBuilder(); Document root = builder.parse(new ByteArrayInputStream(xml)); ret.nodes.add(root); return ret; } catch (FactoryConfigurationError e) { throw new RuntimeException(e); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } catch (SAXException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } public void sort(Comparator<XMLQuery> comparator) { List<XMLQuery> list = new ArrayList<XMLQuery>(nodes.size()); for (Node node : nodes) { list.add(create(node)); } Collections.sort(list, comparator); nodes.clear(); for (XMLQuery parser : list) { nodes.addAll(parser.nodes); } } public static XMLQuery create(Node... list) { return create(Arrays.asList(list)); } }