/*******************************************************************************
* Copyright (c) 2011-2012 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.ws.ui.utils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
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.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.SAXException;
/**
* Utility class for processing SOAP request XML
* @author bfitzpat
*
*/
public class SOAPDOMParser {
Document dom;
TreeParent root;
/**
* Parse the file into the nodes
* @param filepath
*/
public void parseXmlFile(String fileContents){
root = new TreeParent("Invisible Root"); //$NON-NLS-1$
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// clean up the XML a little
String cleanedFileContents = fileContents.trim();
cleanedFileContents = cleanedFileContents.replaceAll("(\\r|\\n)", ""); //$NON-NLS-1$//$NON-NLS-2$
//parse using builder to get DOM representation of the XML file
ByteArrayInputStream bais = new ByteArrayInputStream(cleanedFileContents.getBytes());
dom = db.parse(bais);
dom.getDocumentElement().normalize();
parseDocument();
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
}catch(SAXException se) {
se.printStackTrace();
}catch(IOException ioe) {
ioe.printStackTrace();
}
}
/*
* Work through the configuration
*/
private void parseDocument(){
//get the root elememt
Element docEle = dom.getDocumentElement();
TreeParent soapRoot = new TreeParent(docEle.getTagName());
soapRoot.setData(docEle);
processChildren(soapRoot, docEle);
root.addChild(soapRoot);
}
/*
* Work down the children tree
* @param parent
* @param el
*/
private void processChildren ( TreeParent parent, Element el ) {
el.normalize();
parent.setData(el);
NodeList children = el.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i) instanceof Element) {
Element child = (Element) children.item(i);
String name = child.getTagName();
TreeParent childNode = new TreeParent(name);
processChildren(childNode, child);
parent.addChild(childNode);
}
}
}
/**
* Update the value in the XML
* @param input
* @param tp
* @param value
* @return
*/
public String updateValue ( String input, TreeParent tp, String value) {
parseXmlFile(input);
dom.normalizeDocument();
Element docEle = dom.getDocumentElement();
Element toFind = (Element) tp.getData();
NodeList nl = docEle.getElementsByTagName(toFind.getTagName());
if (nl.getLength() > 0) {
Element found = (Element) nl.item(0);
if (found.getChildNodes() != null && found.getChildNodes().getLength() > 0) {
Node node = found.getChildNodes().item(0);
node.setTextContent(value);
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer;
try {
transformer = transFactory.newTransformer();
StringWriter buffer = new StringWriter();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //$NON-NLS-1$
transformer.transform(new DOMSource(docEle),
new StreamResult(buffer));
String str = buffer.toString();
return str;
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* Return the actual root
* @return
*/
public TreeParent getRoot() {
return this.root;
}
/**
* Pretty print
* @param xml
* @return
*/
public static String prettyPrint ( String xml ) {
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
Document dom;
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
dom = db.parse(bais);
String stringOutput = prettyPrintWithDOM3LS(dom);
return stringOutput;
}catch(ParserConfigurationException pce) {
pce.printStackTrace();
}catch(SAXException se) {
se.printStackTrace();
}catch(IOException ioe) {
ioe.printStackTrace();
}
return null;
}
/*
* @param document
* @return
*/
static String prettyPrintWithDOM3LS(Document document) {
// Pretty-prints a DOM document to XML using DOM Load and Save's LSSerializer.
// Note that the "format-pretty-print" DOM configuration parameter can only be set in JDK 1.6+.
DOMImplementation domImplementation = document.getImplementation();
if (domImplementation.hasFeature("LS", "3.0") && domImplementation.hasFeature("Core", "2.0")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation.getFeature("LS", "3.0"); //$NON-NLS-1$ //$NON-NLS-2$
LSSerializer lsSerializer = domImplementationLS.createLSSerializer();
DOMConfiguration domConfiguration = lsSerializer.getDomConfig();
if (domConfiguration.canSetParameter("format-pretty-print", Boolean.TRUE)) { //$NON-NLS-1$
lsSerializer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); //$NON-NLS-1$
LSOutput lsOutput = domImplementationLS.createLSOutput();
lsOutput.setEncoding("UTF-8"); //$NON-NLS-1$
StringWriter stringWriter = new StringWriter();
lsOutput.setCharacterStream(stringWriter);
lsSerializer.write(document, lsOutput);
return stringWriter.toString();
} else {
throw new RuntimeException("DOMConfiguration 'format-pretty-print' parameter isn't settable."); //$NON-NLS-1$
}
} else {
throw new RuntimeException("DOM 3.0 LS and/or DOM 2.0 Core not supported."); //$NON-NLS-1$
}
}
/**
* from http://jaysonlorenzen.wordpress.com/2009/01/29/48/
* @param inXMLStr
* @return
*/
public static boolean isXMLLike(String inXMLStr) {
boolean retBool = false;
Pattern pattern;
Matcher matcher;
// REGULAR EXPRESSION TO SEE IF IT AT LEAST STARTS AND ENDS
// WITH THE SAME ELEMENT
final String XML_PATTERN_STR = "<(\\S+?)(.*?)>(.*?)</\\1>"; //$NON-NLS-1$
// IF WE HAVE A STRING
if (inXMLStr != null && inXMLStr.trim().length() > 0) {
// IF WE EVEN RESEMBLE XML
if (inXMLStr.trim().startsWith("<")) { //$NON-NLS-1$
pattern = Pattern.compile(XML_PATTERN_STR,
Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE);
// RETURN TRUE IF IT HAS PASSED BOTH TESTS
matcher = pattern.matcher(inXMLStr);
retBool = matcher.matches();
}
// ELSE WE ARE FALSE
}
return retBool;
}
public static boolean isValidXML(String xml) {
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
db.parse(bais);
return true;
}catch(Exception e) {
return false;
}
}
/**
* Simple JSON pretty print to format JSON output
* @param inJSON
* @return
*/
public static String prettyPrintJSON ( String inJSON ) {
int numberOfSpaces = 4;
String spaces = String.format("%" + numberOfSpaces + "s", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
inJSON = inJSON.trim();
if (inJSON.startsWith("{") && inJSON.endsWith("}")) { //$NON-NLS-1$ //$NON-NLS-2$
String output = ""; //$NON-NLS-1$
char[] chars = inJSON.toCharArray();
for (int i = 0; i < chars.length; i++) {
char current = chars[i];
switch (current) {
case '{':
output = output + current + "\r\n" + spaces; //$NON-NLS-1$
break;
case '}':
output = output + "\r\n" + current; //$NON-NLS-1$
break;
case ',':
output = output + current + "\r\n" + spaces; //$NON-NLS-1$
break;
default:
output = output + current;
break;
}
}
return output;
} else if (inJSON.startsWith("[") && inJSON.endsWith("]")) { //$NON-NLS-1$ //$NON-NLS-2$
String output = "[\r\n"; //$NON-NLS-1$
inJSON = inJSON.substring(1, inJSON.length() - 1);
String innerParts = prettyPrintJSON(inJSON);
output = output + innerParts;
output = output + "\r\n]"; //$NON-NLS-1$
return output;
}
return inJSON;
}
}