package com.thoughtworks.winstonwolfe.datasource; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import javax.xml.transform.*; 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.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.io.StringWriter; import java.util.Map; public class ApplyChangesDataSource implements DataSource { private final Map<String, String> selectors; private final Map<String, String> changes; private final DataSource originalDataSource; public ApplyChangesDataSource(Map<String, String> selectors, Map<String, String> changes, DataSource originalDataSource) { this.selectors = selectors; this.changes = changes; this.originalDataSource = originalDataSource; } @Override public String getData() { try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); StreamResult result = new StreamResult(new StringWriter()); DOMSource source = new DOMSource(getDocument()); transformer.transform(source, result); return result.getWriter().toString(); } catch (TransformerException e) { throw new RuntimeException("Could not convert document to string.", e); } } @Override public Document getDocument() { Document document = originalDataSource.getDocument(); XPath xpath = XPathFactory.newInstance().newXPath(); for (String key : changes.keySet()) { try { String newValue = changes.get(key); String selector = selectors.get(key); if (selector == null) { throw new RuntimeException(String.format("Wanted to change '%s' to '%s' but no selector called '%s' was supplied", key, newValue, key)); } NodeList result = (NodeList) xpath.evaluate(selector, document, XPathConstants.NODESET); if (result.getLength() < 1) { throw new RuntimeException(String.format("The Xpath identified as '%s' does not exist in the request", key)); } result.item(0).setTextContent(newValue); } catch (XPathExpressionException e) { throw new RuntimeException(String.format("The xpath '%s' is not valid.", key), e); } } return document; } }