A Bad Design Story—Apex Dom Document XmlNode
Abstract
While doing some coding using the new Apex DOM classes, I felt so frustrated regarding the BAD class design, that I decided to write a post covering my experiences.
Why do DOM documents & XMLNode suck?
Both of the new classes Document and XMLNode miss pretty common and popular DOM methods; here are a few:
getElementsByTagName(String nodeName): Why is this missing? Is it tough for Salesforce developers to expose??
getElementsByPath (String path): Ok, this is missing too. It's tolerable 🙂
addChild(XmlNode node): Why can’t I add a First Class XmlNode inside an XMLNode?
toXmlString(): One has to call DOM.Document.toXMLString(), this prints the whole XML. But I don’t want that big pollution in my logs.
The only relief that XMLNode provides is “getElementByTagName()” as “getChildElement()”. “getElementsByPath()” is not much used by everyone, but “getElementsByTagName()” is really a must-have. So developers might write wrappers to use XmlNode.getChildren or XmlNode.getChildElement to get the missing APIs. But again, every wrapper is apex, and every apex line you write will add to script limits.
But the fact that hurts me the most is missing “addChild(XMLNODE)”. I guess this method is pretty powerful and helps a lot on many occasions; developers who deal with XML parsing know this very well :). Imagine a situation when you have a pretty complex child node that you get from a web service call, and it's supposed to go inside a big XML parent node. I would say Salesforce API team should at least consult the existing XmlDom class for its intuitive design and ease of use.
Apart from that, the API and its documents are both confusing. There are two methods in Dom.XmlNode:
String getAttribute(String key, String keyNamespace)
String getAttributeValue(String key, String keyNamespace)
Apex documentation for both of these is same: “Returns the attribute value for the given key and keyNamespace.” So why the hell are there two APIs that do the same thing, receive the same arguments, and return the same type? Here is the link for Apex Docs. For a quick look, here is the screenshot.
Now I felt the real pain when I started porting an XMLDom-based apex code to Dom.Document/XmlNode. I will not say anything; I will just add code snippets for both; you can feel the pain. The example code below is for parsing a Google Gdata feed.
// USING XMLDOM.cls
public Integer getTotalResults(XMLDom.Element feed) {
Integer intVal = null;
String intValStr = feed.getValue('openSearch:totalResults');
if (intValStr != null) {
intVal = Integer.valueOf(intValStr);
}
return intVal;
}
// Using DOM.XmlNode
public Integer getTotalResults(Dom.XmlNode feed ) {
Integer intVal = null;
// NOTE:
// 1. I have to check if getChildElement is null
// 2. I have include namespace, it doesn't works without that.
String intValStr = feed.getChildElement('openSearch:totalResults','http://www.w3.org/2005/Atom').getText();
if (intValStr != null) {
intVal = Integer.valueOf(intValStr);
}
return intVal;
}
Though most of you already know the design of XmlDom.cls, I am still sharing that below:
I still love the simple design of XmlDom.cls, and wish Salesforce could create a replica of that instead of reinventing the wheel and giving “Document and XmlNode”. This will help to:
Reduce the efforts (code change) required in migrating to the new DOM classes.
Reduce the “learning curve” to almost zero.
Reduce the requirement to fix the API holes by writing wrapper classes.
In the beginning, I was pretty excited about this new Spring 10 API, but the excitement ended soon when I started using it. It's a pain to use and worst design Apex API for me.
References
Let’s Talk!
Drop a note below to move forward with the conversation 👇🏻