Json2XmlMappedConverter.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.io.File;
  22. import java.util.ArrayList;
  23. import java.util.Collections;
  24. import java.util.Comparator;
  25. import java.util.HashMap;
  26. import java.util.List;
  27. import java.util.Map;

  28. import org.openspcoop2.utils.UtilsException;
  29. import org.openspcoop2.utils.json.AbstractUtils;
  30. import org.openspcoop2.utils.json.JSONUtils;
  31. import org.openspcoop2.utils.resources.FileSystemUtilities;
  32. import org.openspcoop2.utils.xml.XMLUtils;
  33. import org.w3c.dom.Node;

  34. import com.fasterxml.jackson.databind.JsonNode;
  35. import com.fasterxml.jackson.databind.node.ObjectNode;

  36. /**
  37.  * @author Bussu Giovanni (bussu@link.it)
  38.  * @author  $Author$
  39.  * @version $Rev$, $Date$
  40.  *
  41.  */
  42. public class Json2XmlMappedConverter extends AbstractMappedConverter {

  43.     private String rootElement_localName = "Root";
  44.     private String rootElement_namespace = null;

  45.     private List<String> attributes = new ArrayList<>();
  46.    
  47.    
  48.     public Json2XmlMappedConverter() {
  49.         this.forceReorder = true; // viene effettuato il riordinamento per ogni operazione di modifica dei nomi, attribute... e' possibile disabilitarlo se si usa il riordinamento manuale
  50.     }
  51.    
  52.    
  53.     // -- RootElement
  54.    
  55.     public void setRootElement(String rootElement) {
  56.         this.rootElement_localName = rootElement;
  57.     }
  58.     public void setRootElement(String rootElement, String namespace) {
  59.         this.rootElement_localName = rootElement;
  60.         this.rootElement_namespace = namespace;
  61.     }
  62.    
  63.     // -- Attributes
  64.    
  65.     public void addAttributeMapping(String path) throws UtilsException {
  66.         this.attributes.add(path);
  67.     }
  68.     public void readAttributeMappingFromFile(String path) throws UtilsException {
  69.         this.readAttributeMappingFromFile(new File(path));
  70.     }
  71.     public void readAttributeMappingFromFile(File path) throws UtilsException {
  72.         if(path.exists()==false) {
  73.             throw new UtilsException("File ["+path.getAbsolutePath()+"] not exists");
  74.         }
  75.         if(path.canRead()==false) {
  76.             throw new UtilsException("File ["+path.getAbsolutePath()+"] cannot read");
  77.         }
  78.         byte [] r = null;
  79.         try {
  80.             r = FileSystemUtilities.readBytesFromFile(path);
  81.         }catch(Exception e) {
  82.             throw new UtilsException(e.getMessage(),e);
  83.         }
  84.         this.readAttributeMappingFromFile(r);
  85.     }
  86.     public void readAttributeMappingFromFile(byte[] resource) throws UtilsException {
  87.         readFileConfig(resource, this.attributes);
  88.     }  
  89.    
  90.    
  91.    
  92.     // -- Convert
  93.    
  94.     public String convert(String json) throws UtilsException {
  95.        
  96.         JSONUtils utils = JSONUtils.getInstance(false);
  97.         JsonNode node = utils.getAsNode(json);
  98.        
  99.         return convert(node);
  100.     }
  101.    
  102.     public String convert(JsonNode node) throws UtilsException {
  103.                
  104.         JSONUtils utils = JSONUtils.getInstance(false);
  105.        
  106.         List<String> attributes_renamed = this.attributes;
  107.         List<String> arrays_renamed = this.arrays;
  108.         List<String> reorderChildren_renamed = this.reorderChildren.keys();
  109.        
  110.         if(!this.renameFields.isEmpty()) {
  111.            
  112.             List<String> keys = this.renameFields.keys();
  113.             Collections.sort(keys, Comparator.reverseOrder());
  114.             for (String path : keys) {
  115.                 String newName = this.renameFields.get(path);
  116.                
  117.                 //System.out.println("RENAME ["+path+"] in ["+newName+"]");
  118.                
  119.                 boolean forceReorder = false;
  120.                 if(this.attributes.contains(path)) {
  121.                     //System.out.println("RENAME ATTRIBUTE ["+newName+"]");
  122.                     this.attributes.remove(path);
  123.                     newName = "@"+newName;
  124.                 }
  125.                 else {
  126.                     forceReorder = this.forceReorder;
  127.                 }

  128.                 //System.out.println("FORCE REORDER: "+forceReorder);
  129.                 utils.renameFieldByPath(node, path, newName, forceReorder, false); // non e' obbligatoria la presenza
  130.             }
  131.            
  132.             // sistemo path negli attributi
  133.             if(!attributes_renamed.isEmpty()) {
  134.                 attributes_renamed = correctPath("attributes",attributes_renamed);
  135.             }
  136.            
  137.             // sistemo path nell'array
  138.             if(!arrays_renamed.isEmpty()) {
  139.                 arrays_renamed = correctPath("arrays", arrays_renamed);
  140.             }
  141.            
  142.             // sistemo path nelle istruzioni di reorder
  143.             if(!reorderChildren_renamed.isEmpty()) {
  144.                 reorderChildren_renamed = correctPath("reorder", reorderChildren_renamed);
  145.             }
  146.            
  147.         }
  148.        
  149.         if(!attributes_renamed.isEmpty()) {
  150.             for (String path : attributes_renamed) {
  151.                
  152.                 @SuppressWarnings("unused")
  153.                 String parentPath = getParentPath(path);
  154.                 String attrName = getLastNamePath(path);
  155.                
  156.                 //System.out.println("ATTRIBUTE ["+path+"] ["+attrName+"]");
  157.                 if(this.camelCase) {
  158.                     attrName = AbstractUtils.camelCase(attrName, this.camelCase_firstLower);
  159.                 }
  160.                 utils.renameFieldByPath(node, path, "@"+attrName, false); // non e' obbligatoria la presenza
  161.             }
  162.         }
  163.        
  164.         if(!arrays_renamed.isEmpty()) {
  165.             for (String path : arrays_renamed) {
  166.                 //System.out.println("ARRAY ["+path+"]");
  167.                 utils.convertFieldToArrayByPath(node, path, this.forceReorder, false); // non e' obbligatoria la presenza
  168.             }
  169.         }
  170.        
  171.         if(!reorderChildren_renamed.isEmpty()) {
  172.             for (String path : reorderChildren_renamed) {
  173.                 String [] children = this.reorderChildren.get(path);
  174.                 //System.out.println("REORDER ["+path+"] ["+children.length+"] ["+java.util.Arrays.asList(children)+"]");
  175.                 utils.reorderFieldChildrenByPath(node, path, false, // non e' obbligatoria la presenza
  176.                         children);
  177.             }
  178.         }
  179.        
  180.         // lasciare come ultimo visto che modifica i nomi
  181.         if(this.camelCase) {
  182.             boolean forceReorder = true; // per mantenere ordine, questo serve sempre
  183.             utils.renameFieldInCamelCase(node, this.camelCase_firstLower, forceReorder);
  184.         }
  185.        
  186.         // Fix: se il nodo json è formato da più elementi, viene convertito solo il primo. Aggiungo un root Element
  187.         JsonNode rootNode = node;
  188.         Map<String, String> map = new HashMap<>();
  189.         if(this.rootElement_localName!=null) {
  190.             rootNode = utils.newObjectNode();
  191.             if(this.rootElement_namespace!=null) {
  192.                 ((ObjectNode)rootNode).set("NS."+this.rootElement_localName, node);
  193.                 map.put(this.rootElement_namespace,"NS");
  194.             }
  195.             else {
  196.                 ((ObjectNode)rootNode).set(this.rootElement_localName, node);
  197.             }
  198.         }
  199.         String json = utils.toString(rootNode);
  200.        
  201.         //System.out.println("JSON: "+json);
  202.        
  203.         IJson2Xml json2xml = Xml2JsonFactory.getJson2XmlMapped(map);
  204.         String xml = json2xml.json2xml(json);
  205.                
  206.         //System.out.println("XML: "+xml);
  207.        
  208.         if(this.prettyPrint) {
  209.             try {
  210.                 Node n = XMLUtils.getInstance().newDocument(xml.getBytes());
  211.                 return org.openspcoop2.utils.xml.PrettyPrintXMLUtils.prettyPrintWithTrAX(n, true);
  212.             }catch(Exception e) {
  213.                 throw new UtilsException(e.getMessage(),e);
  214.             }
  215.         }
  216.        
  217.         return xml;
  218.     }
  219.    
  220. }