Last active
April 12, 2023 15:32
-
-
Save brianmfear/795469a22c52b8b0baf0a153cedc9254 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
global class XmlToJson { | |
// Try to determine some data types by pattern | |
static Pattern | |
boolPat = Pattern.compile('^(true|false)$'), decPat = Pattern.compile('^[-+]?\\d+(\\.\\d+)?$'), | |
datePat = Pattern.compile('^\\d{4}.\\d{2}.\\d{2}$'), | |
timePat = Pattern.compile('^\\d{4}.\\d{2}.\\d{2} (\\d{2}:\\d{2}:\\d{2} ([-+]\\d{2}:\\d{2})?)?$'); | |
// Primary function to decode XML | |
static Map<Object, Object> parseNode(Dom.XmlNode node, Map<Object, Object> parent) { | |
// Iterate over all child elements for a given node | |
for(Dom.XmlNode child: node.getChildElements()) { | |
// Pull out some information | |
String nodeText = child.getText().trim(), name = child.getName(); | |
// Determine data type | |
Object value = | |
// Nothing | |
String.isBlank(nodeText)? null: | |
// Try boolean | |
boolPat.matcher(nodeText).find()? | |
(Object)Boolean.valueOf(nodeText): | |
// Try decimals | |
decPat.matcher(nodeText).find()? | |
(Object)Decimal.valueOf(nodeText): | |
// Try dates | |
datePat.matcher(nodeText).find()? | |
(Object)Date.valueOf(nodeText): | |
// Try times | |
timePat.matcher(nodeText).find()? | |
(Object)DateTime.valueOf(nodeText): | |
// Give up, use plain text | |
(Object)nodeText; | |
// We have some text to process | |
if(value != null) { | |
// We already have a value here, convert it to a list | |
if(parent.containsKey(name)) { | |
try { | |
// We already have a list, so just add it | |
((List<Object>)parent.get(name)).add(value); | |
} catch(Exception e) { | |
// We don't have a list, so convert these two values to a list | |
parent.put(name, new List<Object>{parent.get(name), value}); | |
} | |
} else { | |
// Store a new value | |
parent.put(name, value); | |
} | |
} else if(child.getNodeType() == Dom.XmlNodeType.ELEMENT) { | |
// If it's not a comment or text, we will recursively process the data | |
Map<Object, Object> temp = parseNode(child, new Map<Object, Object>()); | |
// If at least one node was processed, add a new element into the array | |
if(!temp.isEmpty()) { | |
// Again, create or update a list | |
if(parent.containsKey(name)) { | |
try { | |
// If it's already a list, add it | |
((List<Object>)parent.get(name)).add(temp); | |
} catch(Exception e) { | |
// Otherwise, convert the element into a list | |
parent.put(name, new List<Object> { parent.get(name), temp }); | |
} | |
} else { | |
// New element | |
parent.put(name, temp); | |
} | |
} | |
} | |
} | |
return parent; | |
} | |
// This function converts XML into a Map | |
global static Map<Object, Object> parseDocumentToMap(Dom.Document doc) { | |
return parseNode(doc.getRootElement(), new Map<Object, Object>()); | |
} | |
// This function converts XML into a JSON string | |
global static String parseDocumentToJson(Dom.Document doc) { | |
return JSON.serialize(parseDocumentToMap(doc)); | |
} | |
// This function converts XML into a native object | |
// If arrays are expected, but not converted automatically, this call may fail | |
// If so, use the parseDocumentToMap function instead and fix any problems | |
global static Object parseDocumentToObject(Dom.Document doc, Type klass) { | |
return JSON.deserialize(parseDocumentToJson(doc), klass); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@isTest class XmlToJsonTest { | |
@isTest static void test() { | |
Dom.Document doc = new Dom.Document(); | |
doc.load( | |
'<a>'+ | |
'<b><c>Hello World</c><d>2016-05-01</d><e>2016-05-01 11:29:00 +03:00</e><f>true</f><g>3.1415</g><h>Two</h><h>Parts</h></b>'+ | |
'<b><c>Hello World</c><d>2016-05-01</d><e>2016-05-01 11:29:00 +03:00</e><f>true</f><g>3.1415</g><h>Two</h><h>Parts</h></b>'+ | |
'</a>' | |
); | |
A r = (A)XmlToJson.parseDocumentToObject(doc, a.class); | |
System.assertNotEquals(null, r); | |
System.assertNotEquals(null, r.b); | |
for(Integer i = 0; i != 2; i++) { | |
System.assertNotEquals(null, r.b[i].c); | |
System.assertNotEquals(null, r.b[i].d); | |
System.assertNotEquals(null, r.b[i].e); | |
System.assertNotEquals(null, r.b[i].f); | |
System.assertNotEquals(null, r.b[i].g); | |
System.assertNotEquals(null, r.b[i].h); | |
} | |
} | |
class A { | |
B[] b; | |
} | |
class B { | |
String c; | |
Date d; | |
DateTime e; | |
Boolean f; | |
Decimal g; | |
String[] h; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You have written a wonderful code. Actually I was trying to parse xml schema to JSON. My approach was different, Your code was straight forward and cool. I have learnt many things from your code.
Thank You ☺