In Convert JSON to XML I showed how to make XML from JSON. Here’s the opposite. It could be a little more all-encompassing by dealing with dates, and unescaping, but for now, this should serve most simple needs.

There is now a webapp api of this too which you can use to convert online. See Using Apps Script for xml json conversion
How to use

Let’s start with this XML string that needs to be converted to a JSON object.



  some string
  8
  false
  
    
      numbers
      http://numbersapi.com/
    
    
      faa
      http://services.faa.gov/airport/status
    
  
  
    8
    legs an arachnid has
  
  
    8
    furlongs in a mile
  
  1
  2
  3
  

It can be used like this

var obFromXml =  makeObFromXml ( XmlService.parse (xmlString).getRootElement() );

The result

This is able to reverse the conversion done by the second approach used in Convert JSON to XML. Any XML attributes will be converted to regular key/value pairs, since the concept of an attribute doesn't exist in JSON. I did consider creating an attribute object, but in the end decided on this approach where a value and an attribute are considered the same. If an element has both attributes and a text node, the text node will be added to a property called text.
{
 "aString": "some string",
 "aNumber": 8,
 "aBoolean": false,
 "anObject": {
 "apis": [{
 "name": "numbers",
 "url": "http://numbersapi.com/"
 }, {
 "name": "faa",
 "url": "http://services.faa.gov/airport/status"
 }]
 },
 "anArray": [{
 "value": 8,
 "result": "legs an arachnid has"
 }, {
 "value": 8,
 "result": "furlongs in a mile"
 }],
 "anotherArray": [1, 2, 3]
 }

The code

It's recursive, so in the end it's just a few lines of code. Note that it converts numbers and booleans from text in the fixValue function. This could easily be extended to convert dates or unescape strings between JSON and XML formats if necessary.

/**
* traverse an xml tree and create a js object
* @param {XmlElement} xmlElement the parent
* @return {object||string} a new branch
*/
function makeObFromXml(xmlElement) {
  
  // parent for this iteration
  var job = {};
  var name = xmlElement.getName();
  
  // attributes are converted to children
  xmlElement.getAttributes().forEach(function(d) {
    var child = XmlService.createElement(d.getName());
    child.setText(d.getValue());
    xmlElement.addContent(child);
  });
  
  
  // any children
  var kids = xmlElement.getChildren();
  if (!kids.length) {
    // its just a value
    return fixValue(xmlElement.getText());
  } 
  
  else {
    
    // if there are any children we need to recurse
    kids.forEach (function(d) {
      store ( job , d.getName() , makeObFromXml(d));
    });
    
    // if there is also a text node, we need to add that too, but also create a node for it
    store (job , 'text' ,  fixValue(xmlElement.getText()));
    
  }
  return job;
  
  function store( job , name , value ) {
    

    // if it's a repeated key, then we need to turn into an array
    if (job.hasOwnProperty(name) && !Array.isArray (job[name])) {
      job[name] = [job[name]];
    }
    
    // push or assign
    if (value !== '') {
      if (Array.isArray (job[name])) {
        job[name].push (value);
      }
      else {
        job[name] = value;
      }
    }
    
  }
  
  /**
   * converts strings from xml back to regular types
   * @param {string} value the string value
   * @param {*} a native type
   */
  function fixValue (value) {
  
    // is it truthy/falsely
    var lowerValue = value.toLowerCase().trim();
    
    if (lowerValue === false.toString()) return false;
    if (lowerValue === true.toString()) return true;
    
    // is it a number
    if (isFinite(lowerValue) && lowerValue !== '') return new Number (lowerValue);
    
    // just leave it untouched but trimmed
    return value.trim();
  }
  
  }
For more like this see Google Apps Scripts Snippets
Why not join our forum, follow the blog or follow me on Twitter to ensure you get updates when they are available.