JsonXmlPathExpressionEngine.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.utils.xml2json;
import java.util.List;
import org.codehaus.jettison.mapped.Configuration;
import org.openspcoop2.utils.json.JsonPathNotValidException;
import org.openspcoop2.utils.xml.AbstractXPathExpressionEngine;
import org.openspcoop2.utils.xml.DynamicNamespaceContext;
import org.openspcoop2.utils.xml.XPathExpressionEngine;
import org.slf4j.Logger;
import com.jayway.jsonpath.JsonPath;
/**
* PathExpressionEngine
*
* @author Poli Andrea (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class JsonXmlPathExpressionEngine {
private static final String PREFIX = "xpath ";
private static final String NAMESPACE_PREFIX = "namespace("; // namespace
private static final String NAMESPACE_END = ")";
public static void validate(String patternParam, Logger log) throws JsonPathNotValidException {
boolean json2Xml = false;
String pattern = patternParam;
String tipo = "Mapped";
if(patternParam!=null && patternParam.toLowerCase().startsWith(PREFIX.toLowerCase())) {
// default
json2Xml = true;
pattern = patternParam.substring(PREFIX.length());
tipo = "Mapped";
}
if(pattern==null || "".equals(pattern)) {
throw new JsonPathNotValidException("Espressione da utilizzare non fornita");
}
if(!json2Xml) {
try {
JsonPath.compile(pattern);
} catch(Exception e) {
throw new JsonPathNotValidException("Validazione del jsonPath indicato ["+pattern+"] fallita: "+e.getMessage(),e);
}
}
else {
try {
// Wrappo in un unico elemento radice, altrimenti la conversione xml non riesce
pattern = pattern.trim();
if(pattern.toLowerCase().startsWith(NAMESPACE_PREFIX)) {
pattern = pattern.substring(NAMESPACE_PREFIX.length());
if(!pattern.contains(NAMESPACE_END)) {
throw new JsonPathNotValidException("Espressione '"+patternParam+"' in un formato non corretto; non è stata riscontrata la chiusura della definizione dei namespace");
}
int offSet = pattern.indexOf(NAMESPACE_END);
String namespaces = pattern.substring(0, offSet);
if(offSet<(pattern.length()-1)) {
pattern = pattern.substring(offSet+1, pattern.length());
pattern = pattern.trim();
}
else {
pattern = null;
}
if(pattern==null || "".equals(pattern)) {
throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non fornita dopo la dichiarazione dei namespace");
}
//System.out.println("NAMESPACE ["+namespaces+"]");
//System.out.println("PATTERN ["+pattern+"]");
if(namespaces!=null && !"".equals(namespaces)) {
String [] tmp = namespaces.split(",");
if(tmp!=null && tmp.length>0) {
for (String namespaceDeclaration : tmp) {
if(namespaceDeclaration!=null && !"".equals(namespaceDeclaration)) {
if(!namespaceDeclaration.contains(":")) {
throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: atteso ':' separator. ("+namespaces+") ("+namespaceDeclaration+")");
}
else {
int indexOfPrefix = namespaceDeclaration.indexOf(":");
String prefix = namespaceDeclaration.substring(0, indexOfPrefix);
String uri = null;
if(indexOfPrefix<(namespaceDeclaration.length()-1)) {
uri = namespaceDeclaration.substring(indexOfPrefix+1, namespaceDeclaration.length());
}
else {
throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: attesa dichiarazione namespace. ("+namespaces+") ("+namespaceDeclaration+")");
}
prefix = prefix.trim();
uri = uri.trim();
if(prefix==null || "".equals(prefix)) {
throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: prefisso non presente. ("+namespaces+") ("+namespaceDeclaration+")");
}
if(uri==null || "".equals(uri)) {
throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: dichiarazione namespace non presente. ("+namespaces+") ("+namespaceDeclaration+")");
}
//System.out.println("prefix ["+prefix+"] uri["+uri+"]");
}
}
}
}
}
}
AbstractXPathExpressionEngine engine = new XPathExpressionEngine();
engine.validate(pattern);
}
catch(JsonPathNotValidException e) {
throw e;
}
catch(Exception e) {
throw new JsonPathNotValidException("Trasformazione json2xml '"+tipo+"' fallita: "+e.getMessage(),e);
}
}
}
public static String extractAndConvertResultAsString(String elementJson, String pattern, Logger log) throws Exception {
Object o = _extractAndConvertResultAsString(elementJson, pattern, log, false);
if(o!=null) {
return (String) o;
}
return null;
}
@SuppressWarnings("unchecked")
public static List<String> extractAndConvertResultAsList(String elementJson, String pattern, Logger log) throws Exception {
Object o = _extractAndConvertResultAsString(elementJson, pattern, log, true);
if(o!=null) {
return (List<String>) o;
}
return null;
}
private static Object _extractAndConvertResultAsString(String elementJson, String patternParam, Logger log, boolean returnAsList) throws Exception {
IJson2Xml json2Xml = null;
String pattern = patternParam;
String tipo = "Mapped";
if(patternParam!=null && patternParam.toLowerCase().startsWith(PREFIX.toLowerCase())) {
// default
json2Xml = Xml2JsonFactory.getJson2XmlMapped(new Configuration()); // gli altri tipi, jsonML e badgerFished richiedono una struttura json specifica.
pattern = patternParam.substring(PREFIX.length());
tipo = "Mapped";
}
if(pattern==null || "".equals(pattern)) {
throw new Exception("Espressione da utilizzare non fornita");
}
if(json2Xml!=null) {
String node = null;
DynamicNamespaceContext dnc = new DynamicNamespaceContext();
try {
// Wrappo in un unico elemento radice, altrimenti la conversione xml non riesce
String elementJsonWrapped = "{ \"json2xml\" : "+elementJson+" }";
node = json2Xml.json2xml(elementJsonWrapped);
if(node==null || "".equals(node)) {
throw new Exception("xml element ottenuto è vuoto");
}
pattern = pattern.trim();
String namespaces = null;
StringBuilder sbNamespaceDeclarations = new StringBuilder("");
if(pattern.toLowerCase().startsWith(NAMESPACE_PREFIX)) {
pattern = pattern.substring(NAMESPACE_PREFIX.length());
if(!pattern.contains(NAMESPACE_END)) {
throw new Exception("Espressione in un formato non corretto; non è stata riscontrata la chiusura della definizione dei namespace");
}
int offSet = pattern.indexOf(NAMESPACE_END);
namespaces = pattern.substring(0, offSet);
if(offSet<(pattern.length()-1)) {
pattern = pattern.substring(offSet+1, pattern.length());
pattern = pattern.trim();
}
else {
pattern = null;
}
if(pattern==null || "".equals(pattern)) {
throw new Exception("Espressione da utilizzare non fornita dopo la dichiarazione dei namespace");
}
//System.out.println("NAMESPACE ["+namespaces+"]");
//System.out.println("PATTERN ["+pattern+"]");
String newNameXmlns = "___xmlns";
boolean foundXmlns = false;
boolean foundDeclXmlns = false;
if(node.contains("<xmlns:")) {
foundXmlns = true;
node = node.replaceAll("<xmlns:", "<"+newNameXmlns+":");
node = node.replaceAll("</xmlns:", "</"+newNameXmlns+":");
}
if(namespaces!=null && !"".equals(namespaces)) {
String [] tmp = namespaces.split(",");
if(tmp!=null && tmp.length>0) {
for (String namespaceDeclaration : tmp) {
if(namespaceDeclaration!=null && !"".equals(namespaceDeclaration)) {
if(!namespaceDeclaration.contains(":")) {
throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: atteso ':' separator. ("+namespaces+") ("+namespaceDeclaration+")");
}
else {
int indexOfPrefix = namespaceDeclaration.indexOf(":");
String prefix = namespaceDeclaration.substring(0, indexOfPrefix);
String uri = null;
if(indexOfPrefix<(namespaceDeclaration.length()-1)) {
uri = namespaceDeclaration.substring(indexOfPrefix+1, namespaceDeclaration.length());
}
else {
throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: attesa dichiarazione namespace. ("+namespaces+") ("+namespaceDeclaration+")");
}
prefix = prefix.trim();
uri = uri.trim();
if(prefix==null || "".equals(prefix)) {
throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: prefisso non presente. ("+namespaces+") ("+namespaceDeclaration+")");
}
if(uri==null || "".equals(uri)) {
throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: dichiarazione namespace non presente. ("+namespaces+") ("+namespaceDeclaration+")");
}
//System.out.println("prefix ["+prefix+"] uri["+uri+"]");
if(prefix.equals("xmlns")) {
prefix = newNameXmlns;
foundDeclXmlns = true;
}
dnc.addNamespace(prefix, uri);
sbNamespaceDeclarations.append(" xmlns:").append(prefix).append("=\"").append(uri).append("\" ");
}
}
}
}
}
if(foundXmlns && !foundDeclXmlns) {
String prefix = newNameXmlns;
String uri = "http://govway.org/utils/json2xml/xmlns";
dnc.addNamespace(prefix, uri);
sbNamespaceDeclarations.append(" xmlns:").append(prefix).append("=\"").append(uri).append("\" ");
}
}
if(sbNamespaceDeclarations!=null && sbNamespaceDeclarations.length()>0) {
node = node.replaceFirst("<json2xml>", ("<json2xml"+sbNamespaceDeclarations+">"));
}
}catch(Exception e) {
throw new Exception("Trasformazione json2xml '"+tipo+"' fallita: "+e.getMessage(),e);
}
try {
// NOTA: e' importante invocarlo con il corretto metodo
XPathExpressionEngine xPathEngine = new XPathExpressionEngine();
if(returnAsList) {
return AbstractXPathExpressionEngine.extractAndConvertResultAsList(node, dnc, xPathEngine, pattern, log);
}
else {
return AbstractXPathExpressionEngine.extractAndConvertResultAsString(node, dnc, xPathEngine, pattern, log);
}
}catch(Exception e) {
throw new Exception("Trasformazione json2xml '"+tipo+"' fallita: "+e.getMessage()+"\nXml: \n"+node,e);
}
}
if(returnAsList) {
return org.openspcoop2.utils.json.JsonPathExpressionEngine.extractAndConvertResultAsList(elementJson, pattern, log);
}
else {
return org.openspcoop2.utils.json.JsonPathExpressionEngine.extractAndConvertResultAsString(elementJson, pattern, log);
}
}
}