# HG changeset patch
# User František Kučera <franta-hg@frantovo.cz>
# Date 1414542306 -3600
# Node ID e62a3e4982121453512b14ea7201d7b7d546a1d2
# Parent  33b2441a6d3661a9035335b2f3101fd86732e47d
out-xpath: support also node-set (not only primitive type results)

diff -r 33b2441a6d36 -r e62a3e498212 java/alt2xml-out-xpath/src/cz/frantovo/alt2xml/out/xpath/XPathAction.java
--- a/java/alt2xml-out-xpath/src/cz/frantovo/alt2xml/out/xpath/XPathAction.java	Tue Oct 28 17:53:24 2014 +0100
+++ b/java/alt2xml-out-xpath/src/cz/frantovo/alt2xml/out/xpath/XPathAction.java	Wed Oct 29 01:25:06 2014 +0100
@@ -21,17 +21,32 @@
 import cz.frantovo.alt2xml.out.ActionContext;
 import cz.frantovo.alt2xml.out.OutputActionException;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
 import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpression;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  *
@@ -42,9 +57,14 @@
 	public static final String PARAMETER_TYPED_PARAMETERS = "typed-parameters";
 	public static final String PARAMETER_LINE_BREAK = "line-break";
 	public static final String PARAMETER_ENVIRONMENT_VARIABLES = "environment-variables";
+	public static final String PARAMETER_NODE_SET = "node-set";
+	private static final Logger log = Logger.getLogger(XPathAction.class.getName());
 	private final boolean typedParameters;
 	private final boolean lineBreak;
 	private final boolean environmentVariables;
+	private final boolean nodeSet;
+	private final TransformerFactory transformerFactory;
+	private final Transformer copyTransformer;
 	private final XPathFactory xpathFactory;
 	private final XPath xpath;
 	private final String expressionString;
@@ -54,6 +74,14 @@
 		xpathFactory = XPathFactory.newInstance();
 		xpath = xpathFactory.newXPath();
 
+		try {
+			transformerFactory = TransformerFactory.newInstance();
+			copyTransformer = transformerFactory.newTransformer();
+			copyTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+		} catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
+			throw new OutputActionException("Unable to initialize XSLT copying transformer", e);
+		}
+
 		final List<String> actionData = getActionContext().getActionData();
 
 		if (actionData.size() < 1) {
@@ -63,6 +91,7 @@
 			typedParameters = Boolean.parseBoolean(actionContext.getActionProperties().getProperty(PARAMETER_TYPED_PARAMETERS));
 			lineBreak = Boolean.parseBoolean(actionContext.getActionProperties().getProperty(PARAMETER_LINE_BREAK, Boolean.TRUE.toString()));
 			environmentVariables = Boolean.parseBoolean(actionContext.getActionProperties().getProperty(PARAMETER_ENVIRONMENT_VARIABLES, Boolean.FALSE.toString()));
+			nodeSet = Boolean.parseBoolean(actionContext.getActionProperties().getProperty(PARAMETER_NODE_SET, Boolean.FALSE.toString()));
 
 			Map<String, Object> xpathParameters = new HashMap<>();
 
@@ -139,6 +168,16 @@
 		}
 	}
 
+	private String nodeToString(Node node) throws OutputActionException {
+		try {
+			StringWriter w = new StringWriter();
+			copyTransformer.transform(new DOMSource(node), new StreamResult(w));
+			return w.toString();
+		} catch (TransformerException e) {
+			throw new OutputActionException("Unable to convert node to string", e);
+		}
+	}
+
 	@Override
 	public void run(DOMResult domResult) throws OutputActionException {
 		XPathExpression xpathExpression = null;
@@ -153,12 +192,42 @@
 				throw new OutputActionException("Unable to compile XPath: " + expressionString, e);
 			}
 
-			String result = xpathExpression.evaluate(document);
 			try (PrintWriter out = new PrintWriter(getActionContext().getOutputStream())) {
-				out.print(result);
-				if (lineBreak) {
-					out.println();
+
+				if (nodeSet) {
+					NodeList result = (NodeList) xpathExpression.evaluate(document, XPathConstants.NODESET);
+					for (int i = 0; i < result.getLength(); i++) {
+						Node node = result.item(i);
+
+						log.log(Level.FINE, "Node type: {0}", node.getClass());
+
+						final String stringValue;
+
+						if (node instanceof Attr) {
+							Attr attribute = (Attr) node;
+							stringValue = attribute.getValue();
+						} else if (node instanceof Element) {
+							stringValue = nodeToString(node);
+							/**
+							 * TODO: print/log node separator
+							 */
+						} else {
+							stringValue = String.valueOf(node);
+						}
+
+						out.print(stringValue);
+						if (lineBreak) {
+							out.println();
+						}
+					}
+				} else {
+					log.log(Level.FINE, "String value, no node-set");
+					out.print(xpathExpression.evaluate(document));
+					if (lineBreak) {
+						out.println();
+					}
 				}
+
 			}
 		} catch (XPathExpressionException e) {
 			throw new OutputActionException("Unable to evaluate XPath: " + xpathExpression, e);