package net.java.xpath.ui; import java.io.CharArrayReader; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.Iterator; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; 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.TransformerConfigurationException; 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.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.openide.util.Exceptions; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * * @author Michael Bien */ public class XPathEvaluator { private Transformer transformer; private DocumentBuilder docBuilder; public XPathEvaluator() { try { transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); } catch (TransformerConfigurationException ex) { Exceptions.printStackTrace(ex); } try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(false); factory.setValidating(false); docBuilder = factory.newDocumentBuilder(); docBuilder.setEntityResolver(new EntityResolver() { @Override public InputSource resolveEntity(String publicId, String systemId) { return new InputSource(new StringReader("")); } }); } catch (ParserConfigurationException ex) { Exceptions.printStackTrace(ex); } } public String evalXPathToString(String xpath, String xml) throws SAXException, IOException, TransformerException, XPathExpressionException { if (docBuilder == null || transformer == null) { return ""; } NodeList resultXML = (NodeList) evaluate(xpath, xml, XPathConstants.NODESET); if (resultXML.getLength() != 0) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < resultXML.getLength(); i++) { Node item = resultXML.item(i); String nodeValue = item.getNodeValue(); if (nodeValue == null) { StringWriter stringWriter = new StringWriter(); transformer.transform(new DOMSource(item), new StreamResult(stringWriter)); sb.append(stringWriter.toString()); } else { sb.append(item.getNodeValue()).append("\n"); } } return sb.toString(); } else { return ""; } } public Object evaluate(String xpath, String xml, QName ret) throws SAXException, IOException, XPathExpressionException { Document sourceXML = docBuilder.parse(new InputSource(new CharArrayReader(xml.toCharArray()))); XPathFactory factory = XPathFactory.newInstance(); XPath xPath = factory.newXPath(); //hack; found no way to get it working with default namespaces if(sourceXML.lookupNamespaceURI(null) != null) { try { DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance(); fac.setNamespaceAware(false); sourceXML = fac.newDocumentBuilder().parse(new InputSource(new CharArrayReader(xml.toCharArray()))); } catch (ParserConfigurationException ex) {} } xPath.setNamespaceContext(new UniversalNamespaceResolver(sourceXML)); XPathExpression expr = xPath.compile(xpath); return expr.evaluate(sourceXML, ret); } private final static class UniversalNamespaceResolver implements NamespaceContext { private Document sourceDocument; public UniversalNamespaceResolver(Document document) { sourceDocument = document; } @Override public String getNamespaceURI(String prefix) { if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) { return sourceDocument.lookupNamespaceURI(null); } else { return sourceDocument.lookupNamespaceURI(prefix); } } @Override public String getPrefix(String namespaceURI) { return sourceDocument.lookupPrefix(namespaceURI); } @Override public Iterator<?> getPrefixes(String namespaceURI) { return null; } } }