Contact Us:

670 Lafayette Ave, Brooklyn,
NY 11216

+1 800 966 4564
+1 800 9667 4558

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 && 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 && textContent != null && 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);

1 Comment

  1. By
    October 8, 2019

    Really great article and sample code. I think I did find a bug when there is a hierarchy involved in the XML. So for example, I get the following XML back from a web service and the code does not return valid JSON:
    0000000024806ADAP-001ADAPTAVIST INC0001900-01-011THE HOLLAND BUILDING205 PARK CENTRAL EASTSPRINGFIELDMO658060001900-01-012ADAPTAVIST UK SERVICES LTUNIT 2 WATERSIDELONDONN1 7UX0001900-01-01BACS0001900-01-01000001

Leave a comment

Your email address will not be published. Required fields are marked *