Parsing xml in Apex : Converting XML into JSON or Deserializing XML

When you are working on an integration which uses XML instead of JSON then it’s always a pain to parse the XML response in apex. I encountered the same problem and ended up with writing a class which makes this job easier. I think this can help you as well.

XMLParser class has a method xmlToJson which takes a XML string and returns a JSON string.

Example – Following is the xml

<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
   <food>
      <name>Belgian Waffles</name>
      <price>$5.95</price>
      <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
      <calories>650</calories>
   </food>
   <food>
      <name>Strawberry Belgian Waffles</name>
      <price>$7.95</price>
      <description>Light Belgian waffles covered with strawberries and whipped cream</description>
      <calories>900</calories>
   </food>
   <food>
      <name>Berry-Berry Belgian Waffles</name>
      <price>$8.95</price>
      <description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
      <calories>900</calories>
   </food>
   <food>
      <name>French Toast</name>
      <price>$4.50</price>
      <description>Thick slices made from our homemade sourdough bread</description>
      <calories>600</calories>
   </food>
   <food>
      <name>Homestyle Breakfast</name>
      <price>$6.95</price>
      <description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
      <calories>950</calories>
   </food>
</breakfast_menu>

JSON returned by the XMLParser

{
  "breakfast_menu": {
    "food": [
      {
        "name": "Belgian Waffles",
        "price": "$5.95",
        "description": "Two of our famous Belgian Waffles with plenty of real maple syrup",
        "calories": "650"
      },
      {
        "name": "Strawberry Belgian Waffles",
        "price": "$7.95",
        "description": "Light Belgian waffles covered with strawberries and whipped cream",
        "calories": "900"
      },
      {
        "name": "Berry-Berry Belgian Waffles",
        "price": "$8.95",
        "description": "Light Belgian waffles covered with an assortment of fresh berries and whipped cream",
        "calories": "900"
      },
      {
        "name": "French Toast",
        "price": "$4.50",
        "description": "Thick slices made from our homemade sourdough bread",
        "calories": "600"
      },
      {
        "name": "Homestyle Breakfast",
        "price": "$6.95",
        "description": "Two eggs, bacon or sausage, toast, and our ever-popular hash browns",
        "calories": "950"
      }
    ]
  }
}

Syntax

String xml = ''; // XML 
String jsonContent = XmlParser.xmlToJson(xml);

// You can deserailize the xml like we do JSON in apex using JSON.deserilize method

ResponseWrapper rw = (ResponseWrapper) JSON.deserilaize(jsonContent, ResponseWrapper.class);

XMLParser class

/* 
    An utility class to parse XML and create the equivalent JSON
    @author - Naval Sharma
*/
public class XMLParser {
    
    // To find the root element so that we can enclose it in the curly braces 
    public static String rootElementName; 
    
    /* Method which is parsing the XML content into JSON 
     * @param xml : XML String 
     * return     : JSON String
    */
    
    public static String xmlToJson(String xml) {
        
        // Load the xml in the document
        Dom.Document doc = new Dom.Document();
        doc.load(xml);
        Dom.XMLNode root = doc.getRootElement();
        
        // Pass the root element and false as the second parameter
        String jsonContent = XMLParser.parse(root, false);
        
        return jsonContent;
    }
    
    
    /* Method which makes the recursive calls and creates the JSON for
     * each element, it processes each node and finds the attributes and text content of a node
     * @param node      : Dom.XMLNode instance - XML node which will be processed
     * @param isChild   : Boolean - To control the structure of JSON, should be true for child element
     * return           : JSON string 
    */ 
    public static String parse(Dom.XMLNode node, Boolean isChild){
        
        String json = '';
        Boolean isArray = false;
        if ( rootElementName == null ) {
            rootElementName = node.getName();
        }
        
        if ( node.getNodeType() == Dom.XmlNodeType.ELEMENT ){
            
            Map<String, List<String>> mapChildrenJSON = new Map<String, List<String>>();
            List<String> lstJSONForChildren = new List<String>();
            
            // Check whether node has any child
            List<Dom.XMLNode> children = node.getChildElements();
            
            if ( children.size() > 0 ){
            
                // Process all the children in a row
                for ( Dom.XMLNode child : children ){
                    
                    String tmp = parse( child, true );
                    
                    if( tmp != '' ) {
                    
                        if ( !mapChildrenJSON.containsKey( child.getName() ) ){
                        
                            mapChildrenJSON.put( child.getName(), new List<String>() );     
                        
                        }
                        
                        // Add into a map to make a collection for the repeatative child nodes
                        mapChildrenJSON.get( child.getName() ).add( tmp );  
                    
                    }
                    
                } 
                
                // Strcuture the JSON based on the repeation 
                // Should be treated as an array if there are multiple elements with the same node name
                for ( String key : mapChildrenJSON.keySet() ){
                    
                    if ( mapChildrenJSON.get(key).size() > 1 ){
                        if(isChild) {
                        
                            lstJSONForChildren.add( '[' + String.join(mapChildrenJSON.get(key), ', ') + ']' );
                        
                        }
                        else {
                        
                            lstJSONForChildren.add( '"' + key + '": [' + String.join(mapChildrenJSON.get(key), ', ') + ']' );
                                
                        }
                        isArray = true;
                    }
                    else {
                    
                        lstJSONForChildren.add( '"' + key + '": ' + mapChildrenJSON.get(key)[0] );
                    
                    }
                }
            }
            
            // Construc the JSON for all the node attributes 
            List<String> lstAttributes = new List<String>( lstJSONForChildren );
            
            for ( Integer i=0; i<node.getAttributeCount(); i++){
                
                String key = node.getAttributeKeyAt( i );
                String value = node.getAttribute( key, '' );
                lstAttributes.add( '"' + key + '": "' + value + '"' );    
            
            }  
            
            // Look for the text content 
            String textContent = node.getText();
            if ( textContent != null &amp;&amp; textContent.trim() != '' ) {
            
                textContent = textContent.replace( '"', '\\"' );
                lstAttributes.add( '"ele_text": "' + textContent + '"' );  
                  
            }
            if ( !isChild ){
            
                if(!isArray) {
                
                    json = '"' + node.getName() + '": {' + String.join(lstAttributes,  ', ') + '}'; 
                    
                }
                else {
                
                    json = ' {' + String.join(lstAttributes,  ', ') + '}'; 
                    
                }
            }
            else {
                if ( lstAttributes.size() == 1 &amp;&amp; textContent != null &amp;&amp; textContent.trim() != '' ){
                    
                    json = '"' + textContent + '"';
                    
                } 
                else {
                    if(!isArray) {
                    
                        if( lstAttributes.size() > 0 ){
                        
                            json = '{' + String.join(lstAttributes,  ', ') + '}'; 
                            
                        }
                        
                    }
                    else {
                    
                        json = String.join(lstAttributes,  ', '); 
                        
                    }
                }   
            }
        }
        if ( rootElementName == node.getName() ) {
        
            if(!isArray) {
            
                json = '{' + json + '}';
            
            }
            else {
                
                json = '{"' + node.getName() + '" : ' + json + '}';
                
            }
        
        }
        
        system.debug(node.getName()+ ':' + json);
        
        return json;
    }
    
}

Link to GitHub Repository

Deserializing xml into any wrapper class object

String jsonStr = XMLParser.xmlToJson(xmlStr);

WrapperClass wc = (WrapperClass) JSON.class(jsonStr, WrapperClass.class);

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.