/* * Copyright 2013-2014 the original author or authors. * * 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 org.springframework.integration.xml.xpath; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.springframework.integration.xml.DefaultXmlPayloadConverter; import org.springframework.integration.xml.XmlPayloadConverter; import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; import org.springframework.xml.xpath.NodeMapper; import org.springframework.xml.xpath.XPathException; import org.springframework.xml.xpath.XPathExpression; import org.springframework.xml.xpath.XPathExpressionFactory; /** * Utility class for 'xpath' support. * * @author Artem Bilan * @since 3.0 */ public final class XPathUtils { public static final String STRING = "string"; public static final String BOOLEAN = "boolean"; public static final String NUMBER = "number"; public static final String NODE = "node"; public static final String NODE_LIST = "node_list"; public static final String DOCUMENT_LIST = "document_list"; private static List<String> RESULT_TYPES = Arrays.asList(STRING, BOOLEAN, NUMBER, NODE, NODE_LIST, DOCUMENT_LIST); private static XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); /** * Utility method to evaluate an xpath on the provided object. * Delegates evaluation to an {@link XPathExpression}. * Note this method provides the {@code #xpath()} SpEL function. * * * @param o the xml Object for evaluaton. * @param xpath an 'xpath' expression String. * @param resultArg an optional parameter to represent the result type of the xpath evaluation. * Only one argument is allowed, which can be an instance of {@link org.springframework.xml.xpath.NodeMapper} or * one of these String constants: "string", "boolean", "number", "node" or "node_list". * @param <T> The required return type. * @return the result of the xpath expression evaluation. * @throws IllegalArgumentException - if the provided arguments aren't appropriate types or values; * @throws MessagingException - if the provided object can't be converted to a {@link Node}; * @throws XPathException - if the xpath expression can't be evaluated. */ @SuppressWarnings({"unchecked"}) public static <T> T evaluate(Object o, String xpath, Object... resultArg) { Object resultType = null; if (resultArg != null && resultArg.length > 0) { Assert.isTrue(resultArg.length == 1, "'resultArg' can contains only one element."); Assert.noNullElements(resultArg, "'resultArg' can't contains 'null' elements."); resultType = resultArg[0]; } XPathExpression expression = XPathExpressionFactory.createXPathExpression(xpath); Node node = converter.convertToNode(o); if (resultType == null) { return (T) expression.evaluateAsString(node); } else if (resultType instanceof NodeMapper<?>) { return (T) expression.evaluateAsObject(node, (NodeMapper<?>) resultType); } else if (resultType instanceof String && RESULT_TYPES.contains(resultType)) { String resType = (String) resultType; if (DOCUMENT_LIST.equals(resType)) { List<Node> nodeList = (List<Node>) XPathEvaluationType.NODE_LIST_RESULT.evaluateXPath(expression, node); try { DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); List<Node> documents = new ArrayList<Node>(nodeList.size()); for (Node n : nodeList) { Document document = documentBuilder.newDocument(); document.appendChild(document.importNode(n, true)); documents.add(document); } return (T) documents; } catch (ParserConfigurationException e) { throw new XPathException("Unable to create 'documentBuilder'.", e); } } else { XPathEvaluationType evaluationType = XPathEvaluationType.valueOf(resType.toUpperCase() + "_RESULT"); return (T) evaluationType.evaluateXPath(expression, node); } } else { throw new IllegalArgumentException("'resultArg[0]' can be an instance of 'NodeMapper<?>' " + "or one of supported String constants: " + RESULT_TYPES); } } private XPathUtils() { } }