package gov.nih.nci.cagrid.metadata; import java.util.Iterator; import java.util.Map; public class XPathUtils { private static final String LOCAL_REPLACEMENT = "' and local-name()='$1'"; private static final String URI_REPLACEMENT = "*[namespace-uri()='"; private static final String NS_START_REGEX = ":([a-zA-Z]+)"; /** * This utilty takes an xpath that uses namespace prefixes (such as * /a:B/a:C) and converts it to one without prefixes, by using the * appropriate operators instead (such as * /*[namespace-uri()='http://DOMAIN.COM/SCHEMA' and * local-name()='B']/*[namespace-uri()='http://DOMAIN.COM/SCHEMA' and * local-name()='C']). THe only conceivable use for this funciton is to * write sane xpath and convert it to the insane xpath globus index service * supports. * * NOTE: This isn't perfect. The known limitations are: 1) its * overly agressive, and will replace QName-looking string literals, 2) it * won't work if you have namespaces attributes 3) it will silently not * replace any QNames that you haven't supplied a prefix mapping for * * @param prefixedXpath * An xpath [optionally] using namespace prefixes in nodetests * @param namespaces * A Map<String,String> keyed on namespace prefixes to resolve * in the xpath, where the value is the actual namespace that * should be used. * @return a converted, conformant, xpath */ public static String translateXPath(String prefixedXpath, Map namespaces) { // don't process an empty Xpath, or one with not ns prefixes if (prefixedXpath == null || prefixedXpath.trim().length() == 0 || prefixedXpath.indexOf(":") < 0) { return prefixedXpath; } else if (namespaces == null || namespaces.keySet().size() == 0) { throw new IllegalArgumentException( "You specified an XPath with prefixes, yet didn't define any prefix mappings."); } // process all the replacements based on prefixes Iterator iterator = namespaces.keySet().iterator(); while (iterator.hasNext()) { String prefix = (String) iterator.next(); String ns = (String) namespaces.get(prefix); // replace the last thing in the xpath being a qname prefixedXpath = prefixedXpath.replaceAll(prefix + NS_START_REGEX + "[\\s]*$", URI_REPLACEMENT + ns + LOCAL_REPLACEMENT + "]"); // replace any qname that is starting a predicate prefixedXpath = prefixedXpath.replaceAll(prefix + NS_START_REGEX + "\\[", URI_REPLACEMENT + ns + LOCAL_REPLACEMENT + " and "); // replace any other qname (has some character after the qname that // isn't the start of a predicate) prefixedXpath = prefixedXpath.replaceAll(prefix + NS_START_REGEX + "([^\\[]){1,1}", URI_REPLACEMENT + ns + LOCAL_REPLACEMENT + "]$2"); } return prefixedXpath; } }