From bee5dd259a4438d45ecd1bcc26dfba12875236d6 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 26 Jun 2018 11:03:48 +0200 Subject: initial commit --- .../gv/egiz/eaaf/core/impl/utils/XPathUtils.java | 523 +++++++++++++++++++++ 1 file changed, 523 insertions(+) create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java (limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java') diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java new file mode 100644 index 00000000..7df242bd --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java @@ -0,0 +1,523 @@ +/******************************************************************************* + *******************************************************************************/ + + +package at.gv.egiz.eaaf.core.impl.utils; + +import java.util.List; +import java.util.Map; + +import org.jaxen.JaxenException; +import org.jaxen.NamespaceContext; +import org.jaxen.Navigator; +import org.jaxen.SimpleNamespaceContext; +import org.jaxen.dom.DOMXPath; +import org.jaxen.dom.DocumentNavigator; +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 at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants; +import at.gv.egiz.eaaf.core.exceptions.XPathException; + +/** + * 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 Navigator documentNavigator = + DocumentNavigator.getInstance(); + /** The default namespace prefix to namespace URI mappings. */ + private static NamespaceContext NS_CONTEXT; + + static { + SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + ctx.addNamespace(XMLNamespaceConstants.MOA_PREFIX, XMLNamespaceConstants.MOA_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.MOA_CONFIG_PREFIX, XMLNamespaceConstants.MOA_CONFIG_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.MOA_ID_CONFIG_PREFIX, XMLNamespaceConstants.MOA_ID_CONFIG_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.ECDSA_PREFIX, XMLNamespaceConstants.ECDSA_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.PD_PREFIX, XMLNamespaceConstants.PD_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.SAML_PREFIX, XMLNamespaceConstants.SAML_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.SAMLP_PREFIX, XMLNamespaceConstants.SAMLP_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.DSIG_PREFIX, XMLNamespaceConstants.DSIG_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.XSLT_PREFIX, XMLNamespaceConstants.XSLT_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.XSI_PREFIX, XMLNamespaceConstants.XSI_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.DSIG_FILTER2_PREFIX, XMLNamespaceConstants.DSIG_FILTER2_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.DSIG_EC_PREFIX, XMLNamespaceConstants.DSIG_EC_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.MD_PREFIX, XMLNamespaceConstants.MD_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.MDP_PREFIX, XMLNamespaceConstants.MDP_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.MVV_PREFIX, XMLNamespaceConstants.MVV_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.STB_PREFIX, XMLNamespaceConstants.STB_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.WRR_PREFIX, XMLNamespaceConstants.WRR_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.STORK_PREFIX, XMLNamespaceConstants.STORK_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.STORKP_PREFIX, XMLNamespaceConstants.STORKP_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.SAML2_PREFIX, XMLNamespaceConstants.SAML2_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.SAML2P_PREFIX, XMLNamespaceConstants.SAML2P_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.XENC_PREFIX, XMLNamespaceConstants.XENC_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.XADES_1_1_1_NS_PREFIX, XMLNamespaceConstants.XADES_1_1_1_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) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), 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) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), 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) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), 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) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), 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) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), 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. + */ + public 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) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), 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; + } + + /** + * Returns the namespace prefix used within XPathUtils for referring to + * the namespace of the specified (Security Layer command) element. + * + * This namespace prefix can be used in various XPath expression evaluation methods + * within XPathUtils without explicitely binding it to the particular + * namespace. + * + * @param contextElement The (Security Layer command) element. + * + * @return the namespace prefix used within XPathUtils for referring to + * the namespace of the specified (Security Layer command) element. + * + * throws XpathException If the specified element has a namespace other than the ones + * known by this implementation as valid Security Layer namespaces (cf. + * @link Constants#SL10_NS_URI, @link Constants#SL11_NS_URI, @link Constants#SL12_NS_URI). + */ + public static String getSlPrefix (Element contextElement) throws XPathException + { + String sLNamespace = contextElement.getNamespaceURI(); + String sLPrefix = null; + + if (sLNamespace.equals(XMLNamespaceConstants.SL10_NS_URI)) + sLPrefix = XMLNamespaceConstants.SL10_PREFIX; + + else if (sLNamespace.equals(XMLNamespaceConstants.SL12_NS_URI)) + sLPrefix = XMLNamespaceConstants.SL12_PREFIX; + + else if (sLNamespace.equals(XMLNamespaceConstants.SL11_NS_URI)) + sLPrefix = XMLNamespaceConstants.SL11_PREFIX; + + else + throw new XPathException("XPath operation FAILED. Reason: "); + + return sLPrefix; + } + + + /** + * Return the SecurityLayer namespace prefix of the context element. + * If the context element is not the element that lies within the + * SecurityLayer namespace. The Securitylayer namespace is derived from + * the xmlns:sl10, sl11 or sl + * attribute of the context element. + * + * The returned prefix is needed for evaluating XPATH expressions. + * + * @param contextElement The element to get a prefix for the Securitylayer namespace, + * that is used within the corresponding document. + * + * @return The string sl10, sl11 or sl, + * depending on the SecurityLayer namespace of the contextElement. + * + * throws XPathException If no (vlalid) SecurityLayer namespace prefix or namespace + * is defined. + */ + public static String getSlPrefixFromNoRoot (Element contextElement) throws XPathException { + + String slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI); + if (slPrefix == null) + slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI); + + if (slPrefix == null) + slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI); + + return slPrefix; + + } + + /** + * Checks if the context element has an attribute xmlns:slPrefix and + * if the prefix of that attribute corresponds with a valid SecurityLayer namespace. + * + * @param contextElement The element to be checked. + * @param slPrefix The prefix which should be checked. Must be a valid SecurityLayer + * namespace prefix. + * @param slNameSpace The SecurityLayer namespace that corresponds to the specified prefix. + * + * @return The valid SecurityLayer prefix or null if this prefix is + * not used. + * @throws XPathException + */ + private static String checkSLnsDeclaration(Element contextElement, String slPrefix, String slNameSpace) + throws XPathException + { + String nsAtt = "xmlns:" + slPrefix; + String nameSpace = contextElement.getAttribute(nsAtt); + if (nameSpace == "") { + return null; + + } else { + // check if namespace is correct + if (nameSpace.equals(slNameSpace)) + return slPrefix; + else + throw new XPathException("Unknown Namespace declaration"); + + } + } + +} -- cgit v1.2.3