package org.tigris.juxy.xpath; import org.tigris.juxy.util.ArgumentAssert; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactoryConfigurationException; import java.util.*; /** * @author Pavel Sher * 1 */ public class JavaxXPathExpr implements XPathExpr { private XPath xpath; private String expression; private Map namespaces; public JavaxXPathExpr(String expression) throws XPathFactoryConfigurationException { assert expression != null; this.xpath = javax.xml.xpath.XPathFactory.newInstance(javax.xml.xpath.XPathConstants.DOM_OBJECT_MODEL).newXPath(); this.expression = expression; this.namespaces = new HashMap(); } public XPathExpr addNamespace(String prefix, String uri) throws XPathExpressionException { ArgumentAssert.notNull(prefix, "Prefix must not be null"); ArgumentAssert.notEmpty(uri, "URI must not be empty"); namespaces.put(uri, prefix); return this; } public boolean toBoolean(Node node) throws XPathExpressionException { checkNode(node); Boolean result = (Boolean) evaluateXPath(node, XPathConstants.BOOLEAN); return result.booleanValue(); } private void checkNode(Node node) { ArgumentAssert.notNull(node, "Node must not be null"); } public String toString(Node node) throws XPathExpressionException { checkNode(node); return (String) evaluateXPath(node, XPathConstants.STRING); } public int toInt(Node node) throws XPathExpressionException { checkNode(node); Double result = (Double) evaluateXPath(node, XPathConstants.NUMBER); return result.intValue(); } public double toDouble(Node node) throws XPathExpressionException { checkNode(node); Double result = (Double) evaluateXPath(node, XPathConstants.NUMBER); return result.doubleValue(); } public List toNodeList(Node node) throws XPathExpressionException { checkNode(node); NodeList nodes = (NodeList) evaluateXPath(node, XPathConstants.NODESET); List nodeList = new ArrayList(nodes.getLength()); for (int i = 0; i < nodes.getLength(); i++) nodeList.add(nodes.item(i)); return nodeList; } public Node toNode(Node node) throws XPathExpressionException { checkNode(node); return (Node) evaluateXPath(node, XPathConstants.NODE); } public String getExpression() { return expression; } public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof JavaxXPathExpr)) return false; final JavaxXPathExpr java50XPathExpr = (JavaxXPathExpr) o; if (!expression.equals(java50XPathExpr.expression)) return false; return true; } public int hashCode() { return expression.hashCode(); } private Object evaluateXPath(Node node, QName type) throws XPathExpressionException { Object result; try { prepareXPathNamespaces(); result = xpath.evaluate(expression, node, type); } catch (javax.xml.xpath.XPathExpressionException e) { throw new XPathExpressionException("Failed to evaluate XPath expression: " + expression, e); } return result; } private void prepareXPathNamespaces() { xpath.setNamespaceContext(new JuxyNamespaceContext(namespaces)); } class JuxyNamespaceContext implements NamespaceContext { private Map namespaces; // URI is a key, prefix is a value public JuxyNamespaceContext(Map namespaces) { this.namespaces = namespaces; } public String getNamespaceURI(String prefix) { Iterator nsIt = namespaces.entrySet().iterator(); while (nsIt.hasNext()) { Map.Entry e = (Map.Entry) nsIt.next(); String uri = (String) e.getKey(); String pref = (String) e.getValue(); if (prefix.equals(pref)) return uri; } return null; } public String getPrefix(String namespaceURI) { return (String) namespaces.get(namespaceURI); } public Iterator getPrefixes(String namespaceURI) { String prefix = getPrefix(namespaceURI); if (prefix == null) return Collections.emptyList().iterator(); return Arrays.asList(new String[]{prefix}).iterator(); } } }