Java tutorial
/* Copyright 2014 Universidad Politcnica de Madrid - Center for Open Middleware (http://www.centeropenmiddleware.com) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package com.c4om.utils.xmlutils; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jdom2.Attribute; import org.jdom2.Element; import org.jdom2.filter.Filters; import org.jdom2.util.IteratorIterable; import com.google.common.collect.*; /** * Static methods on this class help with some common tasks performed while working * with XPath. * * @author Pablo Alonso Rodrguez (Center for Open Middleware - UPM) * */ public class XPathUtils { /** * Given a {@link List} of {@link Attribute}, this generates a XPath condition that describes it. * That condition is of the form: <code>./@attr1QName='value1' and /@attr2QName='value2' and ... and /@attrNQName='valueN' and count(./@*)=N</code> * @param attributes the list of attributes (as a {@link List} of {@link Attribute} objects) * @return the XPath condition */ public static String generateAttributesFilter(List<Attribute> attributes) { StringBuilder builder = new StringBuilder(); for (Attribute attribute : attributes) { builder.append("./@" + attribute.getQualifiedName() + "='" + attribute.getValue() + "' and "); } builder.append("count(./@*)=" + attributes.size()); String result = builder.toString(); return result; } /** * It returns a path to a single element. The element (and its ancestors) is distinguished via its * attributes set. * @param currentElement the element whose path is to be calculated * @return the path. */ public static String generateAttributeBasedPath(Element currentElement) { return generateAttributeBasedPath(currentElement, null); } /** * It returns a path to a single element. The element (and its ancestors) is distinguished via its * attributes set. * @param currentElement the element whose path is to be calculated * @param contextElement the element to which a relative path will be calculated (null for an absolute path). * @return the path. * @throws IllegalArgumentException if the currentElement is not descendant of the contextElement * */ public static String generateAttributeBasedPath(Element currentElement, Element contextElement) { StringBuilder builder = new StringBuilder(); Element parent = currentElement.getParentElement(); if (contextElement != null) { IteratorIterable<Element> descendants = contextElement.getDescendants(Filters.element()); Set<Element> descendantsSet = ImmutableSet.copyOf((Iterable<Element>) descendants); if (!descendantsSet.contains(currentElement)) { throw new IllegalArgumentException("The provided element is not descendant of the stopElement"); } } if (parent != contextElement) { String pathToParent = generateAttributeBasedPath(parent, contextElement); builder.append(pathToParent); } else if (contextElement != null) { builder.insert(0, "."); } builder.append("/"); builder.append(currentElement.getQualifiedName()); String filter = "[" + generateAttributesFilter(currentElement.getAttributes()) + "]"; builder.append(filter); String result = builder.toString(); return result; } /** * Given a path of the form <code>{doc|document}('<i>aDoc.xml</i>')<i>/aPath</i></code>, it divides it into the doc and the path * @param pathWithDoc a path starting with the XPath 'doc' function or the XSLT 'document' function. * @return a string array such that array[0]=<i>docPath</i>, array[1]=<i>path</i> and array[2]=<i>pathWithoutRootElement</i> */ public static String[] divideDocAndPath(String pathWithDoc) { String[] result = new String[3]; final String REGEXP_SEARCH = "^(doc|document)\\('(?<docName>.+)'\\)(?<path>/[^\\[\\]/]+(\\[.+\\])?(?<pathWithoutRoot>/.+))$"; Pattern patternToSearch = Pattern.compile(REGEXP_SEARCH); Matcher matcher = patternToSearch.matcher(pathWithDoc); matcher.matches(); result[0] = matcher.group("docName"); result[1] = matcher.group("path"); result[2] = matcher.group("pathWithoutRoot"); return result; } /** * Private constructor to prevent instantiation. */ private XPathUtils() { } }