
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);
By Naveen Sharma
October 8, 2019Really 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