Search code examples
apigee

JsonToXML Array within Array with Different Parent Names in Apigee


I am trying to build an XML structure for a WSDL call, since there isn't a real proper way to send an arbitary size list of complex objects using the parameter passing method, I decided to use Json to XML. Here is my basic Json

school:{
  teachers : [
    {students :[{name: student1}, {name: student2}], name : teacher1},
    {students :[{name: student3}, {name: student4}], name : teacher2}
  ]
}

and what I want to see as an end result is

<school>
  <teachers>
    <name>teacher1</name>
    <students>
      <name>student1</name>
      <name>student2</name>
    </students>
  </teachers>
  <teachers>
    <name>teacher1</name>
    <students>
      <name>student1</name>
      <name>student2</name>
    </students>
  </teachers>
</school>

Using what Apigee Documentation

<ArrayRootElementName>Teachers</ArrayRootElementName>

It still would handle the Students properly, in fact it changes my Students to Teachers. Can someone help please.


Solution

  • To get the XML you desire out of the JSONToXML Policy, you must shape the input JSON differently. The input to JSONToXML should look like this:

    {
      "school": {
        "teachers": [
          {
            "students": {
              "name": [
                "student1",
                "student2"
              ]
            },
            "name": "teacher1"
          },
          {
            "students": {
              "name": [
                "student3",
                "student4"
              ]
            },
            "name": "teacher2"
          }
        ]
      }
    }
    

    But your input isn't like that. How do you get it to look like that?

    You can do it with a Javascript transform. Use a Javascript to re-map the original JSON to the JSON you want. Here's an example:

    var c = context.getVariable('response.content') + '',
        body = JSON.parse(c);
    
    if (body.school) {
      if (body.school.teachers) {
        body.school.teachers.forEach(function(item){
          if (item.students) {
            item.students = fixupStudents(item.students);
          }  
        });
        //body.school.teachers = fixupTeachers(body.school.teachers);
      }
    }
    

    the function fixupStudents looks like this:

    function fixupArray(obj, propName, accessor) {
      var type = Object.prototype.toString.call(obj), i,
          a = [], rval = {};
      if (null !== obj) {
        if (type === "[object Array]") {
          for (i=0; i<obj.length; i++) {
            a.push(accessor(obj[i])); // string
          }
          rval[propName] = a;
        }
      }
      return rval;
    }
    
    function fixupStudents(obj) {
      return fixupArray(obj, 'name', function(o){return o.name;});
    }
    

    Here's a gist that will do the trick.

    You must run this JS step BEFORE the JSONToXML step.