The Extensible Markup Language was hot back in 1997. Unfortunately, this is 2020.

I have been working on an interface for a popular enterprise-class API that is probably as old as Methuselah. I spend a good bit of my time being spoiled by modern APIs; POST a JSON object to and endpoint and get a JSON response back once you work out authentication and all the fun things that entails.

I enjoy a good challenge so I got to work. This was a SOAP endpoint so it was a little bit painful to get it running; the last time I used SOAP was probably back when CFMX 6 was king. Internally we use JSON to move data around so the first step was to iterate through the object and build out the SOAP envelope. Once that was done it was just a matter of posting to the web service.

Next it was just a matter of getting the response from the service and transforming the XML back into JSON so our systems could understand it. This is where the plot thickens.

There were two main problems, one problem I created and the other was because the response being returned was verbose. I mean very verbose. Some responses were upwards of 200kb. Since we are going back to the 90s here, one response would have been large enough to almost fill up a 5.25" floppy disc. To compound the issue, the old method I wrote to transform XML to JSON could take anywhere between one and three seconds complete. That is an eternity for an API.

Doing some digging, I found it was pretty easy to drop into Java and use the org.json.XML java parser to handle the transform which runs faster than my function, but it does not solve the issue of the large payload. I did however find an old GitHub gist by Ben Nadel that helped me trim down my heavyweight XML response.

function deleteNodes(required any nodes) {
 if(!isArray(nodes)){
  var n = argument.nodes;
  argument.nodes = [n];
 }
 for(var node in arguments.nodes){
  variables.parentNode = node.getParentNode();
  if(variables.keyExists("parentNode")){
   variables.prevNode = node.getPreviousSibling();
   if(variables.keyExists("prevNode")){
    variables.parentNode.removeChild(variables.prevNode.getNextSibling());
   }
   else{
    variables.parentNode.removeChild(variables.parentNode.getFirstChild());
   }
  }
 }
}
deleteNodes: Ben Nadel's function rewritten for CFScript

That is a line-for-line copy of Ben's code condensed and rewritten in cfscript. That code is only marginally older than XML, but much like XML, it still works.

Lastly, I just needed to search the XML for the nodes I wanted to get rid of, namely the very verbose message blocks

	cfhttp(url = endpoint, method = "post", timeout="1", throwonerror = "true"){
     cfhttpparam(type = "header", name = "Content-Type", value = "application/soap+xml");
     cfhttpparam(type = "xml", value = envelope);
    }
	var doc = xmlParse(cfhttp.fileContent);
    var children = xmlSearch(doc, "//*[name()='MESSAGE']");
    deleteNodes(children);

Once the cfhttp call completes I call xmlParse on the response. Using xmlSearch I find all the nodes in the XML named MESSAGE, the name of the errant field. That returns an array of fields that need to be removed with deleteNodes Ben was kind enough to provide. The resulting doc is then passed passed to the XML to JSON transform to generate a nice clean result.

Well, I never thought I would be writing a post on XML in 2020, yet here we are. Maybe I will bust out some CFWindow posts next week. Nothing is off the table this year.