Seeing inconsistent JSON response from xmltojson policy

Not applicable

we are using XMLto JSON policy in our API, noticed that this policy converts xml list to JSON array or object based the number of occurances, that is if its single occurrence it converts to object and for multiple converts to array. So the output of this policy is inconsistent. Is there any way we can have a consistent JSON response ?

example:when there are two students in a class, below response is returned.

{ "classList": { "class": [ { "name": "test1", "number": "A01" }, { "name": "test2", "number": "A02" } ] } }

example:when there are one student in a class, below response is returned.

{ "classList": { "class": { "name": "test1", "number": "A01" } } }

but we are expecting as

{ "classList": { "class": [ { "name": "test1", "number": "A01" } ] } }

Solved Solved
1 6 1,185
1 ACCEPTED SOLUTION

Update: The XMLToJSON policy now has an option to address this problem. The workaround described here still works, but there may be a better, easier way to solve the problem. See more details here.

Yes, the policy uses a heuristic to decide whether the thing to be converted is a simple object or an array of objects. The heuristic is simple: if there are multiple child elements with the same name, then obviously it is an array. If there is one child element, then obviously not an array. This heuristic works for most cases, but unfortunately it does not work for one particular element in your particular case. You want, for just one particular element, a single occurrence to be converted into an array, with a length of one.

The way I would do this: post-process the generated JSON. You could do this with a simple Javascript callout. It would examine the class member, and if it is an object, and not an array, it would simply convert it. The code for the callout would look like this:

var bodyContent = JSON.parse(response.content);
if (bodyContent.classList && 
    bodyContent.classList.class && 
    bodyContent.classList.class.constructor !== Array) {
  // new array containing one element
  bodyContent.classList.class = [bodyContent.classList.class]; 
}
// pretty-print the result, append a newline: 
response.content = JSON.stringify(bodyContent, null, 2)+'\n';
// use the following for non-pretty-printed JSON
// response.content = JSON.stringify(bodyContent);

This assumes that the result of XML2JSON has been placed into the 'response' within Edge. Insert this into a JavaScript callout policy, and make that policy execute after the XML2JSON policy.

This approach will work for any element; the code above would need to be modified to specifically test the elements that you wish to convert to arrays.

View solution in original post

6 REPLIES 6

Update: The XMLToJSON policy now has an option to address this problem. The workaround described here still works, but there may be a better, easier way to solve the problem. See more details here.

Yes, the policy uses a heuristic to decide whether the thing to be converted is a simple object or an array of objects. The heuristic is simple: if there are multiple child elements with the same name, then obviously it is an array. If there is one child element, then obviously not an array. This heuristic works for most cases, but unfortunately it does not work for one particular element in your particular case. You want, for just one particular element, a single occurrence to be converted into an array, with a length of one.

The way I would do this: post-process the generated JSON. You could do this with a simple Javascript callout. It would examine the class member, and if it is an object, and not an array, it would simply convert it. The code for the callout would look like this:

var bodyContent = JSON.parse(response.content);
if (bodyContent.classList && 
    bodyContent.classList.class && 
    bodyContent.classList.class.constructor !== Array) {
  // new array containing one element
  bodyContent.classList.class = [bodyContent.classList.class]; 
}
// pretty-print the result, append a newline: 
response.content = JSON.stringify(bodyContent, null, 2)+'\n';
// use the following for non-pretty-printed JSON
// response.content = JSON.stringify(bodyContent);

This assumes that the result of XML2JSON has been placed into the 'response' within Edge. Insert this into a JavaScript callout policy, and make that policy execute after the XML2JSON policy.

This approach will work for any element; the code above would need to be modified to specifically test the elements that you wish to convert to arrays.

Thanks Dino for the details, that really helped. Also on the same note, currently we are dealing with complex xmls with many such occurrences of complex types/lists in different API proxies. So even in this case, is the best solution is have modfiyJSON js in each API proxy and handle API specific types in the script?

Is there any option of referring XSD (schema) in xmltojson policy along with xml content, in order to determine type definitions during conversion?

Thank You

Best Regards

Prasanth

hi Prasanth - yes, if you have the XSD, then in theory you could generalize the Javascript to array-ize just the elements that have maxOccurs > 0. If you send me your XSD, and a real XML document conforming to that XSD, I can try that out for you.

Thanks Dino, please find attached one such sample.

Best Regards

Prasanth

Another option I can tell you. Better yet, you yourself can familiarize yourself with all the materials on EssayServiceScanner . It is an alternative to all methods and is a public assistant.