io.cloudslang.content.xml.utils.XmlUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cs-xml Show documentation
Show all versions of cs-xml Show documentation
Actions for xml processing
The newest version!
/*
* (c) Copyright 2019 EntIT Software LLC, a Micro Focus company, L.P.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Apache License v2.0 which accompany this distribution.
*
* The Apache License is available 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 io.cloudslang.content.xml.utils;
import io.cloudslang.content.httpclient.services.HttpClientService;
import io.cloudslang.content.httpclient.entities.HttpClientInputs;
import io.cloudslang.content.httpclient.build.auth.AuthTypes;
import io.cloudslang.content.xml.entities.SimpleNamespaceContext;
import io.cloudslang.content.xml.entities.inputs.CommonInputs;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpGet;
import org.jdom2.input.SAXBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
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 java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import static org.apache.commons.lang3.StringUtils.EMPTY;
/**
* Created by markowis on 23/02/2016.
*/
public class XmlUtils {
private static final String OK_STATUS_CODE = "200";
private XmlUtils() {
}
public static String nodeToString(Node node) throws TransformerException {
if (node == null) {
return EMPTY;
} else if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
return node.toString();
} else {
return transformElementNode(node);
}
}
/**
* Returns the Namespaces context from an xml.
*
* @param xmlString xml as string
* @param xmlFilePath path to xml file
* @return the Namespaces context from an xml.
* @throws IOException file reading exception
* @throws XMLStreamException parsing exception
*/
public static NamespaceContext getNamespaceContext(String xmlString, String xmlFilePath) throws Exception {
InputStream inputXML = getStream(xmlString, xmlFilePath);
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = inputFactory.createXMLStreamReader(inputXML);
Map namespaces = new HashMap<>();
while (reader.hasNext()) {
int evt = reader.next();
if (evt == XMLStreamConstants.START_ELEMENT) {
QName qName = reader.getName();
if (qName != null) {
if (qName.getPrefix() != null && qName.getPrefix().compareTo("") != 0)
namespaces.put(qName.getPrefix(), qName.getNamespaceURI());
}
}
}
return new SimpleNamespaceContext(namespaces);
}
public static Document parseXmlStringSecurely(String xmlDocument, boolean secure) throws Exception {
DocumentBuilder builder = getDocumentBuilder(secure);
return builder.parse(new InputSource(new StringReader(xmlDocument)));
}
public static DocumentBuilder getDocumentBuilder(boolean secure) throws ParserConfigurationException {
String feature;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
feature = "http://xml.org/sax/features/external-general-entities";
factory.setFeature(feature, false);
feature = "http://xml.org/sax/features/external-parameter-entities";
factory.setFeature(feature, false);
feature = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
factory.setFeature(feature, false);
feature = "http://apache.org/xml/features/disallow-doctype-decl";
factory.setFeature(feature, true);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
factory.setNamespaceAware(true);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, secure);
return factory.newDocumentBuilder();
}
/**
* This method creates an XML document from a given path which respects the encoding specified in the xml header. Otherwise it defaults to UTF-8.
*
* @param path xml given path
* @param secure secure
* @return created xml document form the given path
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*/
public static Document createDocumentFromFile(String path, boolean secure) throws IOException, ParserConfigurationException, SAXException {
DocumentBuilder builder = XmlUtils.getDocumentBuilder(secure);
File initialFile = new File(path);
InputStream targetStream = new FileInputStream(initialFile);
InputSource is = new InputSource(targetStream);
return builder.parse(is);
}
public static void parseXmlString(String xml, String features) throws Exception {
parseXmlInputStream(getStream(xml, EMPTY), features);
}
public static void parseXmlFile(String xmlFile, String features) throws Exception {
parseXmlInputStream(getStream(EMPTY, xmlFile), features);
}
/**
* Transforms a String or File provided by path to a Document object.
*
* @param xml xml the xml as String
* @param filePath the path/remote path to the file
* @param features parsing features to set on the document builder
* @return a Document representation of the String or file
* @throws Exception in case something goes wrong
*/
public static Document createDocument(String xml, String filePath, String features) throws Exception {
try {
return parseXmlInputStream(getStream(xml, filePath), features);
} catch (MalformedURLException e) {
throw new Exception((new StringBuilder("Unable to open remote file requested, file path[")).append(filePath).append("], error[").append(e.getMessage()).append("]").toString(), e);
} catch (IOException e) {
throw new Exception((new StringBuilder("Unable to open file requested, filename[")).append(filePath).append("], error[").append(e.getMessage()).append("]").toString(), e);
}
}
public static Document parseXmlInputStream(InputStream inputStream, String features) throws Exception {
Document xmlDocument;
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
XmlUtils.setFeatures(builderFactory, features);
builderFactory.setNamespaceAware(true);
DocumentBuilder builder = builderFactory.newDocumentBuilder();
xmlDocument = builder.parse(inputStream);
return xmlDocument;
}
/**
* Return all the nodes in an Document for a given XPath.
*
* @param doc the document to read from
* @param pathToNode the XPath to find
* @return a NodeList object
* @throws XPathExpressionException if xpath exception occurred
*/
public static NodeList readNode(Document doc, String pathToNode, NamespaceContext ctx) throws XPathExpressionException {
XPath xPath = createXpath();
xPath.setNamespaceContext(ctx);
return (NodeList) xPath.evaluate(pathToNode, doc, XPathConstants.NODESET);
}
/**
* Transforms a string representation of an XML Node to an Node
*
* @param value the node as String
* @param features parsing features to set on the document builder
* @return the Node object
* @throws Exception in case the String can't be represented as a Node
*/
public static Node stringToNode(String value, String encoding, String features) throws Exception {
Node node;
if (StringUtils.isEmpty(encoding)) {
encoding = "UTF-8";
}
try (InputStream inputStream = new ByteArrayInputStream(value.getBytes(encoding))) {
// check if input value is a Node
Document docNew = DocumentUtils.createDocumentBuilder(features).parse(inputStream);
node = docNew.getDocumentElement();
} catch (SAXException se) {
throw new Exception("Value " + value + "is not valid XML element : " + se.getMessage());
}
return node;
}
/**
* Returns a new instance of XPath.
*
* @return XPath object
*/
private static XPath createXpath() {
return XPathFactory.newInstance().newXPath();
}
/**
* Returns the InputStream representation of a file or string.
*
* @param xml xml the xml as String
* @param filePath he path/remote path to the file
* @return the InputStream representation of a file or string
* @throws IOException Exception in case something goes wrong
*/
public static InputStream getStream(String xml, String filePath) throws IOException {
InputStream inputXML;
if (StringUtils.isEmpty(filePath)) {
inputXML = new ByteArrayInputStream(xml.getBytes());
} else {
if (filePath.startsWith(Constants.Inputs.HTTP_PREFIX_STRING) || filePath.startsWith(Constants.Inputs.HTTPS_PREFIX_STRING)) {
inputXML = new java.net.URL(filePath).openStream();
} else {
inputXML = new FileInputStream(new File(filePath));
}
}
return inputXML;
}
public static StringWriter getStringWriter(Document doc) throws TransformerException {
DOMSource domSource = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult streamResult = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, streamResult);
return writer;
}
public static NodeList evaluateXPathQuery(Document doc, NamespaceContext context, String xPathQuery) throws XPathExpressionException {
XPathExpression expr = createXPathExpression(context, xPathQuery);
return (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
}
public static XPathExpression createXPathExpression(NamespaceContext context, String xPathQuery) throws XPathExpressionException {
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(context);
return xpath.compile(xPathQuery);
}
public static void validateNodeList(NodeList nodeList) throws Exception {
if (nodeList.getLength() == 0) {
throw new Exception(Constants.ErrorMessages.ELEMENT_NOT_FOUND);
}
}
private static String transformElementNode(Node node) throws TransformerException {
StringWriter stringWriter = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, Constants.YES);
transformer.setOutputProperty(OutputKeys.INDENT, Constants.YES);
transformer.transform(new DOMSource(node), new StreamResult(stringWriter));
return stringWriter.toString().trim();
}
public static Document getDocument(CommonInputs commonInputs) throws Exception {
Document doc;
if (Constants.XML_PATH.equalsIgnoreCase(commonInputs.getXmlDocumentSource())) {
doc = XmlUtils.createDocumentFromFile(commonInputs.getXmlDocument(), commonInputs.getSecureProcessing());
} else {
doc = XmlUtils.parseXmlStringSecurely(commonInputs.getXmlDocument(), commonInputs.getSecureProcessing());
}
return doc;
}
public static NamespaceContext getNamespaceContext(CommonInputs commonInputs, Document doc) throws Exception {
NamespaceContext context;
if (Constants.XML_PATH.equalsIgnoreCase(commonInputs.getXmlDocumentSource())) {
StringWriter writer = XmlUtils.getStringWriter(doc);
context = XmlUtils.getNamespaceContext(writer.toString(), "");
} else {
context = XmlUtils.getNamespaceContext(commonInputs.getXmlDocument(), "");
}
return context;
}
public static String createXmlDocumentFromUrl(CommonInputs commonInputs) throws ParserConfigurationException, SAXException, IOException {
HttpClientService scoreHttpClient = new HttpClientService();
HttpClientInputs httpClientInputs = new HttpClientInputs();
httpClientInputs.setMethod(HttpGet.METHOD_NAME);
httpClientInputs.setUrl(commonInputs.getXmlDocument());
if (commonInputs.getUsername().isEmpty()) {
httpClientInputs.setAuthType(AuthTypes.ANONYMOUS);
} else {
httpClientInputs.setAuthType(AuthTypes.BASIC);
httpClientInputs.setUsername(commonInputs.getUsername());
httpClientInputs.setPassword(commonInputs.getPassword());
}
httpClientInputs.setRequestCharacterSet(StandardCharsets.UTF_8.toString());
httpClientInputs.setResponseCharacterSet(StandardCharsets.UTF_8.toString());
httpClientInputs.setTrustAllRoots(commonInputs.getTrustAllRoots());
httpClientInputs.setKeystore(commonInputs.getKeystore());
httpClientInputs.setKeystorePassword(commonInputs.getKeystorePassword());
httpClientInputs.setTrustKeystore(commonInputs.getTrustKeystore());
httpClientInputs.setTrustPassword(commonInputs.getTrustPassword());
httpClientInputs.setX509HostnameVerifier(commonInputs.getX509Hostnameverifier());
httpClientInputs.setProxyHost(commonInputs.getProxyHost());
httpClientInputs.setProxyPort(commonInputs.getProxyPort());
httpClientInputs.setProxyUsername(commonInputs.getProxyUsername());
httpClientInputs.setProxyPassword(commonInputs.getProxyPassword());
Map requestResponse = scoreHttpClient.execute(httpClientInputs);
if (!OK_STATUS_CODE.equals(requestResponse.get(HttpClientService.STATUS_CODE))) {
throw new RuntimeException("Http request to specified URL: " + commonInputs.getXmlDocument() + " failed with status code: " + requestResponse.get(HttpClientService.STATUS_CODE) + ". Request response is: " + requestResponse.get(Constants.Outputs.RETURN_RESULT));
}
return requestResponse.get(Constants.Outputs.RETURN_RESULT);
}
public static void setFeatures(DocumentBuilderFactory reader, String features) throws ParserConfigurationException {
if (StringUtils.isNotBlank(features)) {
Map featuresMap = parseFeatures(features);
for (Object o : featuresMap.keySet()) {
String key = (String) o;
reader.setFeature(key, (Boolean) featuresMap.get(key));
}
}
}
public static void setFeatures(SAXBuilder reader, String features) throws SAXException {
if (!StringUtils.isEmpty(features)) {
Map featuresMap = parseFeatures(features);
for (String key : featuresMap.keySet()) {
reader.setFeature(key, featuresMap.get(key));
}
}
}
private static Map parseFeatures(String features) {
Map map = new HashMap<>();
String[] featuresList = features.split("\\n");
int len$ = featuresList.length;
for (int i$ = 0; i$ < len$; ++i$) {
String element = featuresList[i$];
String[] keyValue = element.split("\\s");
if (keyValue.length != 2) {
throw new IllegalArgumentException("Wrong format for \'features\' input field!");
}
map.put(keyValue[0], Boolean.valueOf(keyValue[1]));
}
return map;
}
}