JsonXmlPathExpressionEngine.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.xml2json;

  21. import java.util.List;

  22. import org.codehaus.jettison.mapped.Configuration;
  23. import org.openspcoop2.utils.json.JsonPathNotValidException;
  24. import org.openspcoop2.utils.xml.AbstractXPathExpressionEngine;
  25. import org.openspcoop2.utils.xml.DynamicNamespaceContext;
  26. import org.openspcoop2.utils.xml.XPathExpressionEngine;
  27. import org.slf4j.Logger;

  28. import com.jayway.jsonpath.JsonPath;

  29. /**
  30.  * PathExpressionEngine
  31.  *
  32.  * @author Poli Andrea (apoli@link.it)
  33.  * @author $Author$
  34.  * @version $Rev$, $Date$
  35.  */
  36. public class JsonXmlPathExpressionEngine {

  37.     private static final String PREFIX = "xpath ";
  38.     private static final String NAMESPACE_PREFIX = "namespace("; // namespace
  39.     private static final String NAMESPACE_END = ")";
  40.    
  41.     public static void validate(String patternParam, Logger log) throws JsonPathNotValidException {
  42.        
  43.         boolean json2Xml = false;
  44.         String pattern = patternParam;
  45.         String tipo = "Mapped";
  46.         if(patternParam!=null && patternParam.toLowerCase().startsWith(PREFIX.toLowerCase())) {
  47.             // default
  48.             json2Xml = true;
  49.             pattern = patternParam.substring(PREFIX.length());
  50.             tipo = "Mapped";
  51.         }
  52.         if(pattern==null || "".equals(pattern)) {
  53.             throw new JsonPathNotValidException("Espressione da utilizzare non fornita");
  54.         }
  55.                
  56.         if(!json2Xml) {
  57.             try {
  58.                 JsonPath.compile(pattern);
  59.             } catch(Exception e) {
  60.                 throw new JsonPathNotValidException("Validazione del jsonPath indicato ["+pattern+"] fallita: "+e.getMessage(),e);
  61.             }
  62.         }
  63.        
  64.         else {
  65.             try {
  66.                 // Wrappo in un unico elemento radice, altrimenti la conversione xml non riesce
  67.                
  68.                 pattern = pattern.trim();
  69.                
  70.                 if(pattern.toLowerCase().startsWith(NAMESPACE_PREFIX)) {
  71.                     pattern = pattern.substring(NAMESPACE_PREFIX.length());
  72.                     if(!pattern.contains(NAMESPACE_END)) {
  73.                         throw new JsonPathNotValidException("Espressione '"+patternParam+"' in un formato non corretto; non è stata riscontrata la chiusura della definizione dei namespace");
  74.                     }
  75.                     int offSet = pattern.indexOf(NAMESPACE_END);
  76.                     String namespaces = pattern.substring(0, offSet);
  77.                     if(offSet<(pattern.length()-1)) {
  78.                         pattern = pattern.substring(offSet+1, pattern.length());
  79.                         pattern = pattern.trim();
  80.                     }
  81.                     else {
  82.                         pattern = null;
  83.                     }
  84.                    
  85.                     if(pattern==null || "".equals(pattern)) {
  86.                         throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non fornita dopo la dichiarazione dei namespace");
  87.                     }
  88.                     //System.out.println("NAMESPACE ["+namespaces+"]");
  89.                     //System.out.println("PATTERN ["+pattern+"]");

  90.                     if(namespaces!=null && !"".equals(namespaces)) {
  91.                        
  92.                         String [] tmp = namespaces.split(",");
  93.                         if(tmp!=null && tmp.length>0) {
  94.                             for (String namespaceDeclaration : tmp) {
  95.                                 if(namespaceDeclaration!=null && !"".equals(namespaceDeclaration)) {
  96.                                     if(!namespaceDeclaration.contains(":")) {
  97.                                         throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: atteso ':' separator. ("+namespaces+") ("+namespaceDeclaration+")");
  98.                                     }
  99.                                     else {
  100.                                         int indexOfPrefix = namespaceDeclaration.indexOf(":");
  101.                                         String prefix = namespaceDeclaration.substring(0, indexOfPrefix);
  102.                                         String uri = null;
  103.                                         if(indexOfPrefix<(namespaceDeclaration.length()-1)) {
  104.                                             uri = namespaceDeclaration.substring(indexOfPrefix+1, namespaceDeclaration.length());
  105.                                         }
  106.                                         else {
  107.                                             throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: attesa dichiarazione namespace. ("+namespaces+") ("+namespaceDeclaration+")");
  108.                                         }
  109.                                         prefix = prefix.trim();
  110.                                         uri = uri.trim();
  111.                                         if(prefix==null || "".equals(prefix)) {
  112.                                             throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: prefisso non presente. ("+namespaces+") ("+namespaceDeclaration+")");
  113.                                         }
  114.                                         if(uri==null || "".equals(uri)) {
  115.                                             throw new JsonPathNotValidException("Espressione '"+patternParam+"' da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: dichiarazione namespace non presente. ("+namespaces+") ("+namespaceDeclaration+")");
  116.                                         }
  117.                                         //System.out.println("prefix ["+prefix+"] uri["+uri+"]");
  118.                                     }
  119.                                 }
  120.                             }
  121.                         }
  122.                     }
  123.                    
  124.                 }
  125.                
  126.                 AbstractXPathExpressionEngine engine = new XPathExpressionEngine();
  127.                 engine.validate(pattern);
  128.                
  129.             }
  130.             catch(JsonPathNotValidException e) {
  131.                 throw e;
  132.             }
  133.             catch(Exception e) {
  134.                 throw new JsonPathNotValidException("Trasformazione json2xml '"+tipo+"' fallita: "+e.getMessage(),e);
  135.             }
  136.         }
  137.        
  138.     }
  139.    
  140.    
  141.     public static String extractAndConvertResultAsString(String elementJson, String pattern, Logger log) throws Exception {
  142.         Object o = _extractAndConvertResultAsString(elementJson, pattern, log, false);
  143.         if(o!=null) {
  144.             return (String) o;
  145.         }
  146.         return null;
  147.     }
  148.     @SuppressWarnings("unchecked")
  149.     public static List<String> extractAndConvertResultAsList(String elementJson, String pattern, Logger log) throws Exception {
  150.         Object o = _extractAndConvertResultAsString(elementJson, pattern, log, true);
  151.         if(o!=null) {
  152.             return (List<String>) o;
  153.         }
  154.         return null;
  155.     }
  156.     private static Object _extractAndConvertResultAsString(String elementJson, String patternParam, Logger log, boolean returnAsList) throws Exception {
  157.            
  158.         IJson2Xml json2Xml = null;
  159.         String pattern = patternParam;
  160.         String tipo = "Mapped";
  161.         if(patternParam!=null && patternParam.toLowerCase().startsWith(PREFIX.toLowerCase())) {
  162.             // default
  163.             json2Xml = Xml2JsonFactory.getJson2XmlMapped(new Configuration()); // gli altri tipi, jsonML e badgerFished richiedono una struttura json specifica.
  164.             pattern = patternParam.substring(PREFIX.length());
  165.             tipo = "Mapped";
  166.         }
  167.         if(pattern==null || "".equals(pattern)) {
  168.             throw new Exception("Espressione da utilizzare non fornita");
  169.         }
  170.                
  171.         if(json2Xml!=null) {
  172.             String node = null;
  173.             DynamicNamespaceContext dnc = new DynamicNamespaceContext();        
  174.             try {
  175.                 // Wrappo in un unico elemento radice, altrimenti la conversione xml non riesce
  176.                 String elementJsonWrapped = "{ \"json2xml\" : "+elementJson+" }";              
  177.                 node = json2Xml.json2xml(elementJsonWrapped);
  178.                 if(node==null || "".equals(node)) {
  179.                     throw new Exception("xml element ottenuto è vuoto");
  180.                 }
  181.                 pattern = pattern.trim();
  182.                 String namespaces = null;
  183.                 StringBuilder sbNamespaceDeclarations = new StringBuilder("");
  184.                 if(pattern.toLowerCase().startsWith(NAMESPACE_PREFIX)) {
  185.                     pattern = pattern.substring(NAMESPACE_PREFIX.length());
  186.                     if(!pattern.contains(NAMESPACE_END)) {
  187.                         throw new Exception("Espressione in un formato non corretto; non è stata riscontrata la chiusura della definizione dei namespace");
  188.                     }
  189.                     int offSet = pattern.indexOf(NAMESPACE_END);
  190.                     namespaces = pattern.substring(0, offSet);
  191.                     if(offSet<(pattern.length()-1)) {
  192.                         pattern = pattern.substring(offSet+1, pattern.length());
  193.                         pattern = pattern.trim();
  194.                     }
  195.                     else {
  196.                         pattern = null;
  197.                     }
  198.                    
  199.                     if(pattern==null || "".equals(pattern)) {
  200.                         throw new Exception("Espressione da utilizzare non fornita dopo la dichiarazione dei namespace");
  201.                     }
  202.                     //System.out.println("NAMESPACE ["+namespaces+"]");
  203.                     //System.out.println("PATTERN ["+pattern+"]");
  204.                    
  205.                     String newNameXmlns = "___xmlns";
  206.                     boolean foundXmlns = false;
  207.                     boolean foundDeclXmlns = false;
  208.                     if(node.contains("<xmlns:")) {
  209.                         foundXmlns = true;
  210.                         node = node.replaceAll("<xmlns:", "<"+newNameXmlns+":");
  211.                         node = node.replaceAll("</xmlns:", "</"+newNameXmlns+":");
  212.                     }
  213.                    
  214.                     if(namespaces!=null && !"".equals(namespaces)) {
  215.                        
  216.                         String [] tmp = namespaces.split(",");
  217.                         if(tmp!=null && tmp.length>0) {
  218.                             for (String namespaceDeclaration : tmp) {
  219.                                 if(namespaceDeclaration!=null && !"".equals(namespaceDeclaration)) {
  220.                                     if(!namespaceDeclaration.contains(":")) {
  221.                                         throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: atteso ':' separator. ("+namespaces+") ("+namespaceDeclaration+")");
  222.                                     }
  223.                                     else {
  224.                                         int indexOfPrefix = namespaceDeclaration.indexOf(":");
  225.                                         String prefix = namespaceDeclaration.substring(0, indexOfPrefix);
  226.                                         String uri = null;
  227.                                         if(indexOfPrefix<(namespaceDeclaration.length()-1)) {
  228.                                             uri = namespaceDeclaration.substring(indexOfPrefix+1, namespaceDeclaration.length());
  229.                                         }
  230.                                         else {
  231.                                             throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: attesa dichiarazione namespace. ("+namespaces+") ("+namespaceDeclaration+")");
  232.                                         }
  233.                                         prefix = prefix.trim();
  234.                                         uri = uri.trim();
  235.                                         if(prefix==null || "".equals(prefix)) {
  236.                                             throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: prefisso non presente. ("+namespaces+") ("+namespaceDeclaration+")");
  237.                                         }
  238.                                         if(uri==null || "".equals(uri)) {
  239.                                             throw new Exception("Espressione da utilizzare non corretta; dichiarazione dei namespace in un formato non corretto: dichiarazione namespace non presente. ("+namespaces+") ("+namespaceDeclaration+")");
  240.                                         }
  241.                                         //System.out.println("prefix ["+prefix+"] uri["+uri+"]");
  242.                                         if(prefix.equals("xmlns")) {
  243.                                             prefix = newNameXmlns;
  244.                                             foundDeclXmlns = true;
  245.                                         }
  246.                                         dnc.addNamespace(prefix, uri);
  247.                                         sbNamespaceDeclarations.append(" xmlns:").append(prefix).append("=\"").append(uri).append("\" ");
  248.                                     }
  249.                                 }
  250.                             }
  251.                         }
  252.                     }
  253.                    
  254.                     if(foundXmlns && !foundDeclXmlns) {
  255.                         String prefix = newNameXmlns;
  256.                         String uri = "http://govway.org/utils/json2xml/xmlns";
  257.                         dnc.addNamespace(prefix, uri);
  258.                         sbNamespaceDeclarations.append(" xmlns:").append(prefix).append("=\"").append(uri).append("\" ");
  259.                     }
  260.                    
  261.                 }
  262.                
  263.                 if(sbNamespaceDeclarations!=null && sbNamespaceDeclarations.length()>0) {
  264.                     node = node.replaceFirst("<json2xml>", ("<json2xml"+sbNamespaceDeclarations+">"));
  265.                 }
  266.                
  267.             }catch(Exception e) {
  268.                 throw new Exception("Trasformazione json2xml '"+tipo+"' fallita: "+e.getMessage(),e);
  269.             }
  270.             try {      
  271.                 // NOTA: e' importante invocarlo con il corretto metodo
  272.                 XPathExpressionEngine xPathEngine = new XPathExpressionEngine();
  273.                 if(returnAsList) {
  274.                     return AbstractXPathExpressionEngine.extractAndConvertResultAsList(node, dnc, xPathEngine, pattern, log);
  275.                 }
  276.                 else {
  277.                     return AbstractXPathExpressionEngine.extractAndConvertResultAsString(node, dnc, xPathEngine, pattern, log);
  278.                 }
  279.             }catch(Exception e) {
  280.                 throw new Exception("Trasformazione json2xml '"+tipo+"' fallita: "+e.getMessage()+"\nXml: \n"+node,e);
  281.             }
  282.         }
  283.        
  284.         if(returnAsList) {
  285.             return org.openspcoop2.utils.json.JsonPathExpressionEngine.extractAndConvertResultAsList(elementJson, pattern, log);
  286.         }
  287.         else {
  288.             return org.openspcoop2.utils.json.JsonPathExpressionEngine.extractAndConvertResultAsString(elementJson, pattern, log);
  289.         }
  290.     }
  291. }