franta-hg@43: /** franta-hg@43: * Alt2XML franta-hg@43: * Copyright © 2014 František Kučera (frantovo.cz) franta-hg@43: * franta-hg@43: * This program is free software: you can redistribute it and/or modify franta-hg@43: * it under the terms of the GNU General Public License as published by franta-hg@43: * the Free Software Foundation, either version 3 of the License, or franta-hg@43: * (at your option) any later version. franta-hg@43: * franta-hg@43: * This program is distributed in the hope that it will be useful, franta-hg@43: * but WITHOUT ANY WARRANTY; without even the implied warranty of franta-hg@43: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the franta-hg@43: * GNU General Public License for more details. franta-hg@43: * franta-hg@43: * You should have received a copy of the GNU General Public License franta-hg@43: * along with this program. If not, see . franta-hg@43: */ franta-hg@49: package cz.frantovo.alt2xml.out.xpath; franta-hg@43: franta-hg@63: import cz.frantovo.alt2xml.out.AbstractDOMAction; franta-hg@43: import cz.frantovo.alt2xml.out.ActionContext; franta-hg@49: import cz.frantovo.alt2xml.out.OutputActionException; franta-hg@63: import java.io.PrintWriter; franta-hg@72: import java.util.Arrays; franta-hg@69: import java.util.HashMap; franta-hg@69: import java.util.List; franta-hg@69: import java.util.Map; franta-hg@63: import javax.xml.transform.dom.DOMResult; franta-hg@63: import javax.xml.xpath.XPath; franta-hg@63: import javax.xml.xpath.XPathExpression; franta-hg@63: import javax.xml.xpath.XPathExpressionException; franta-hg@63: import javax.xml.xpath.XPathFactory; franta-hg@97: import javax.xml.xpath.XPathVariableResolver; franta-hg@101: import org.w3c.dom.Node; franta-hg@43: franta-hg@43: /** franta-hg@43: * franta-hg@43: * @author Ing. František Kučera (frantovo.cz) franta-hg@43: */ franta-hg@63: public class XPathAction extends AbstractDOMAction { franta-hg@43: franta-hg@69: public static final String PARAMETER_TYPED_PARAMETERS = "typed-parameters"; franta-hg@79: public static final String PARAMETER_LINE_BREAK = "line-break"; franta-hg@97: public static final String PARAMETER_ENVIRONMENT_VARIABLES = "environment-variables"; franta-hg@79: private final boolean typedParameters; franta-hg@79: private final boolean lineBreak; franta-hg@97: private final boolean environmentVariables; franta-hg@66: private final XPathFactory xpathFactory; franta-hg@66: private final XPath xpath; franta-hg@68: private final String expressionString; franta-hg@66: franta-hg@68: public XPathAction(ActionContext actionContext) throws OutputActionException { franta-hg@43: super(actionContext); franta-hg@66: xpathFactory = XPathFactory.newInstance(); franta-hg@66: xpath = xpathFactory.newXPath(); franta-hg@43: franta-hg@69: final List actionData = getActionContext().getActionData(); franta-hg@63: franta-hg@69: if (actionData.size() < 1) { franta-hg@69: throw new OutputActionException("Please specify the XPath expression as action data"); franta-hg@69: } else { franta-hg@69: franta-hg@79: typedParameters = Boolean.parseBoolean(actionContext.getActionProperties().getProperty(PARAMETER_TYPED_PARAMETERS)); franta-hg@79: lineBreak = Boolean.parseBoolean(actionContext.getActionProperties().getProperty(PARAMETER_LINE_BREAK, Boolean.TRUE.toString())); franta-hg@97: environmentVariables = Boolean.parseBoolean(actionContext.getActionProperties().getProperty(PARAMETER_ENVIRONMENT_VARIABLES, Boolean.FALSE.toString())); franta-hg@69: franta-hg@69: Map xpathParameters = new HashMap<>(); franta-hg@69: franta-hg@69: for (int i = 1; i < actionData.size(); i++) { franta-hg@69: String parameterName = actionData.get(i++); franta-hg@72: String parameterType = typedParameters ? actionData.get(i++) : PARAMETER_TYPE.STRING.name(); franta-hg@71: Object parameterValue = parseParameterValue(parameterType, actionData.get(i)); franta-hg@69: xpathParameters.put(parameterName, parameterValue); franta-hg@69: } franta-hg@69: franta-hg@97: XPathVariableResolver cliVariableResolver = new PropertiesVariableResolver(xpathParameters); franta-hg@97: XPathVariableResolver variableResolver = environmentVariables ? new CompoundVariableResolver(cliVariableResolver, new EnvironmentVariableResolver()) : cliVariableResolver; franta-hg@97: franta-hg@97: xpath.setXPathVariableResolver(variableResolver); franta-hg@69: franta-hg@69: expressionString = actionData.get(0); franta-hg@63: } franta-hg@43: } franta-hg@68: franta-hg@72: private enum PARAMETER_TYPE { franta-hg@72: franta-hg@72: // TODO: wait for Java 8 widespread and rewrite with lambdas :-) franta-hg@72: STRING { franta-hg@72: @Override franta-hg@72: public Object parse(String value) { franta-hg@72: return value; franta-hg@72: } franta-hg@72: }, franta-hg@72: BOOLEAN { franta-hg@72: @Override franta-hg@72: public Object parse(String value) { franta-hg@72: return Boolean.valueOf(value); franta-hg@72: } franta-hg@72: }, franta-hg@72: INTEGER { franta-hg@72: @Override franta-hg@72: public Object parse(String value) { franta-hg@72: return Integer.parseInt(value); franta-hg@72: } franta-hg@72: }, franta-hg@72: LONG { franta-hg@72: @Override franta-hg@72: public Object parse(String value) { franta-hg@72: return Long.parseLong(value); franta-hg@72: } franta-hg@72: }, franta-hg@72: DOUBLE { franta-hg@72: @Override franta-hg@72: public Object parse(String value) { franta-hg@72: return Double.parseDouble(value); franta-hg@72: } franta-hg@72: }; franta-hg@72: franta-hg@72: public abstract Object parse(String value); franta-hg@72: franta-hg@72: } franta-hg@72: franta-hg@72: private static Object parseParameterValue(String type, String value) throws OutputActionException { franta-hg@72: franta-hg@72: try { franta-hg@72: PARAMETER_TYPE parameterType = PARAMETER_TYPE.valueOf(type.toUpperCase()); franta-hg@72: franta-hg@72: try { franta-hg@72: return parameterType.parse(value); franta-hg@72: } catch (IllegalArgumentException e) { franta-hg@72: throw new OutputActionException("Unable to parse value: „" + value + "“ as " + parameterType.name()); franta-hg@72: } franta-hg@72: } catch (IllegalArgumentException e) { franta-hg@72: throw new OutputActionException( franta-hg@72: "Invalid XPath parameter type: „" + type franta-hg@72: + "“. Possible values are: " + Arrays.toString(PARAMETER_TYPE.values()) franta-hg@72: + " and are case insensitive.", franta-hg@72: e); franta-hg@72: } franta-hg@69: } franta-hg@69: franta-hg@68: @Override franta-hg@68: public void run(DOMResult domResult) throws OutputActionException { franta-hg@101: XPathExpression xpathExpression = null; franta-hg@68: try { franta-hg@101: Node document = domResult.getNode(); franta-hg@101: franta-hg@101: xpath.setNamespaceContext(new DocumentNamespaceContext(document)); franta-hg@101: franta-hg@101: try { franta-hg@101: xpathExpression = xpath.compile(expressionString); franta-hg@101: } catch (XPathExpressionException e) { franta-hg@101: throw new OutputActionException("Unable to compile XPath: " + expressionString, e); franta-hg@101: } franta-hg@101: franta-hg@101: String result = xpathExpression.evaluate(document); franta-hg@68: try (PrintWriter out = new PrintWriter(getActionContext().getOutputStream())) { franta-hg@79: out.print(result); franta-hg@79: if (lineBreak) { franta-hg@79: out.println(); franta-hg@79: } franta-hg@68: } franta-hg@68: } catch (XPathExpressionException e) { franta-hg@68: throw new OutputActionException("Unable to evaluate XPath: " + xpathExpression, e); franta-hg@68: } franta-hg@68: } franta-hg@43: }