package at.gv.egovernment.moa.util; import java.util.List; import java.util.Map; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.traversal.NodeIterator; import org.jaxen.JaxenException; import org.jaxen.NamespaceContext; import org.jaxen.SimpleNamespaceContext; import org.jaxen.dom.DOMXPath; import org.jaxen.dom.DocumentNavigator; /** * Utility methods to evaluate XPath expressions on DOM nodes. * * @author Patrick Peck * @version $Id$ */ public class XPathUtils { /** * The XPath expression selecting all nodes under a given root (including the * root node itself). */ public static final String ALL_NODES_XPATH = "(.//. | .//@* | .//namespace::*)"; /** The DocumentNavigator to use for navigating the document. */ private static DocumentNavigator documentNavigator = DocumentNavigator.getInstance(); /** The default namespace prefix to namespace URI mappings. */ private static NamespaceContext NS_CONTEXT; static { SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addNamespace(Constants.MOA_PREFIX, Constants.MOA_NS_URI); ctx.addNamespace(Constants.MOA_CONFIG_PREFIX, Constants.MOA_CONFIG_NS_URI); ctx.addNamespace( Constants.MOA_ID_CONFIG_PREFIX, Constants.MOA_ID_CONFIG_NS_URI); ctx.addNamespace(Constants.SL10_PREFIX, Constants.SL10_NS_URI); ctx.addNamespace(Constants.SL11_PREFIX, Constants.SL11_NS_URI); ctx.addNamespace(Constants.ECDSA_PREFIX, Constants.ECDSA_NS_URI); ctx.addNamespace(Constants.PD_PREFIX, Constants.PD_NS_URI); ctx.addNamespace(Constants.SAML_PREFIX, Constants.SAML_NS_URI); ctx.addNamespace(Constants.SAMLP_PREFIX, Constants.SAMLP_NS_URI); ctx.addNamespace(Constants.DSIG_PREFIX, Constants.DSIG_NS_URI); ctx.addNamespace(Constants.XSLT_PREFIX, Constants.XSLT_NS_URI); ctx.addNamespace(Constants.XSI_PREFIX, Constants.XSI_NS_URI); ctx.addNamespace( Constants.DSIG_FILTER2_PREFIX, Constants.DSIG_FILTER2_NS_URI); ctx.addNamespace(Constants.DSIG_EC_PREFIX, Constants.DSIG_EC_NS_URI); NS_CONTEXT = ctx; } /** * Return a NodeIterator over the nodes matching the XPath * expression. * * All namespace URIs and prefixes declared in the Constants * interface are used for resolving namespaces. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ public static NodeIterator selectNodeIterator(Node contextNode, String exp) throws XPathException { return selectNodeIterator(contextNode, NS_CONTEXT, exp); } /** * Return a NodeIterator over the nodes matching the XPath * expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param namespaceElement An element from which to build the * namespace mapping for evaluating the XPath expression * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ public static NodeIterator selectNodeIterator( Node contextNode, Element namespaceElement, String exp) throws XPathException { try { SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addElementNamespaces(documentNavigator, namespaceElement); return selectNodeIterator(contextNode, ctx, exp); } catch (JaxenException e) { MessageProvider msg = MessageProvider.getInstance(); String message = msg.getMessage("xpath.00", new Object[] { exp }); throw new XPathException(message, e); } } /** * Return a NodeIterator over the nodes matching the XPath * expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param namespaceMapping A namespace prefix to namespace URI mapping * (String to String) for evaluating the XPath * expression. * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ public static NodeIterator selectNodeIterator( Node contextNode, Map namespaceMapping, String exp) throws XPathException { SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); return selectNodeIterator(contextNode, ctx, exp); } /** * Return a NodeIterator over the nodes matching the XPath * expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param nsContext The NamespaceContext for resolving namespace * prefixes to namespace URIs for evaluating the XPath expression. * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ private static NodeIterator selectNodeIterator( Node contextNode, NamespaceContext nsContext, String exp) throws XPathException { try { DOMXPath xpath = new DOMXPath(exp); List nodes; xpath.setNamespaceContext(nsContext); nodes = xpath.selectNodes(contextNode); return new NodeIteratorAdapter(nodes.listIterator()); } catch (JaxenException e) { MessageProvider msg = MessageProvider.getInstance(); String message = msg.getMessage("xpath.00", new Object[] { exp }); throw new XPathException(message, e); } } /** * Return a NodeList of all the nodes matching the XPath * expression. * * All namespace URIs and prefixes declared in the Constants * interface are used for resolving namespaces. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ public static NodeList selectNodeList(Node contextNode, String exp) throws XPathException { return selectNodeList(contextNode, NS_CONTEXT, exp); } /** * Return a NodeList of all the nodes matching the XPath * expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param namespaceElement An element from which to build the * namespace mapping for evaluating the XPath expression * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ public static NodeList selectNodeList( Node contextNode, Element namespaceElement, String exp) throws XPathException { try { SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addElementNamespaces(documentNavigator, namespaceElement); return selectNodeList(contextNode, ctx, exp); } catch (JaxenException e) { MessageProvider msg = MessageProvider.getInstance(); String message = msg.getMessage("xpath.00", new Object[] { exp }); throw new XPathException(message, e); } } /** * Return a NodeList of all the nodes matching the XPath * expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param namespaceMapping A namespace prefix to namespace URI mapping * (String to String) for evaluating the XPath * expression. * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ public static NodeList selectNodeList( Node contextNode, Map namespaceMapping, String exp) throws XPathException { SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); return selectNodeList(contextNode, ctx, exp); } /** * Return a NodeList of all the nodes matching the XPath * expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param nsContext The NamespaceContext for resolving namespace * prefixes to namespace URIs for evaluating the XPath expression. * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ private static NodeList selectNodeList( Node contextNode, NamespaceContext nsContext, String exp) throws XPathException { try { DOMXPath xpath = new DOMXPath(exp); List nodes; xpath.setNamespaceContext(nsContext); nodes = xpath.selectNodes(contextNode); return new NodeListAdapter(nodes); } catch (JaxenException e) { MessageProvider msg = MessageProvider.getInstance(); String message = msg.getMessage("xpath.00", new Object[] { exp }); throw new XPathException(message, e); } } /** * Select the first node matching an XPath expression. * * All namespace URIs and prefixes declared in the Constants * interface are used for resolving namespaces. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param exp The XPath expression to evaluate. * @return Node The first node matching the XPath expression, or * null, if no node matched. * @throws XPathException An error occurred evaluating the XPath expression. */ public static Node selectSingleNode(Node contextNode, String exp) throws XPathException { return selectSingleNode(contextNode, NS_CONTEXT, exp); } /** * Select the first node matching an XPath expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param namespaceElement An element from which to build the * namespace mapping for evaluating the XPath expression * @param exp The XPath expression to evaluate. * @return Node The first node matching the XPath expression, or * null, if no node matched. * @throws XPathException An error occurred evaluating the XPath expression. */ public static Node selectSingleNode( Node contextNode, Element namespaceElement, String exp) throws XPathException { try { SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addElementNamespaces(documentNavigator, namespaceElement); return selectSingleNode(contextNode, ctx, exp); } catch (JaxenException e) { MessageProvider msg = MessageProvider.getInstance(); String message = msg.getMessage("xpath.00", new Object[] { exp }); throw new XPathException(message, e); } } /** * Select the first node matching an XPath expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param namespaceMapping A namespace prefix to namespace URI mapping * (String to String) for evaluating the XPath * expression. * @param exp The XPath expression to evaluate. * @return Node The first node matching the XPath expression, or * null, if no node matched. * @throws XPathException An error occurred evaluating the XPath expression. */ public static Node selectSingleNode( Node contextNode, Map namespaceMapping, String exp) throws XPathException { SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); return selectSingleNode(contextNode, ctx, exp); } /** * Select the first node matching an XPath expression. * * @param contextNode The root node from which to evaluate the XPath * expression. * @param nsContext The NamespaceContext for resolving namespace * prefixes to namespace URIs for evaluating the XPath expression. * @param exp The XPath expression to evaluate. * @return Node The first node matching the XPath expression, or * null, if no node matched. * @throws XPathException An error occurred evaluating the XPath expression. */ private static Node selectSingleNode( Node contextNode, NamespaceContext nsContext, String exp) throws XPathException { try { DOMXPath xpath = new DOMXPath(exp); xpath.setNamespaceContext(nsContext); return (Node) xpath.selectSingleNode(contextNode); } catch (JaxenException e) { MessageProvider msg = MessageProvider.getInstance(); String message = msg.getMessage("xpath.00", new Object[] { exp }); throw new XPathException(message, e); } } /** * Return the value of a DOM element whose location is given by an XPath * expression. * * @param root The root element from which to evaluate the XPath. * @param xpath The XPath expression pointing to the element whose value * to return. * @param def The default value to return, if no element can be found using * the given xpath. * @return The element value, if it can be located using the * xpath. Otherwise, def is returned. */ public static String getElementValue( Element root, String xpath, String def) { Element elem = (Element) XPathUtils.selectSingleNode(root, xpath); return elem != null ? DOMUtils.getText(elem) : def; } /** * Return the value of a DOM attribute whose location is given by an XPath * expression. * * @param root The root element from which to evaluate the XPath. * @param xpath The XPath expression pointing to the attribute whose value to * return. * @param def The default value to return, if no attribute can be found using * the given xpath. * @return The element value, if it can be located using the * xpath. Otherwise, def is returned. */ public static String getAttributeValue( Element root, String xpath, String def) { Attr attr = (Attr) XPathUtils.selectSingleNode(root, xpath); return attr != null ? attr.getValue() : def; } }