February 4, 2010

Apex Dom Document XmlNode bad design story

Abstract

While doing some coding using the new Apex DOM classes I felt so frustrated regarding BAD BAD class design, that I decided to write a post covering my experiences. For checking the good parts of API please check my previous post.

Why DOM Document & XMLNode sucks ?

Both of the new classes Document and XMLNode miss pretty common and popular DOM methods for ex.

  • getElementsByTagName(String nodeName) : Why this is missing, is it tough for Salesforce developers to expose ??
  • getElementsByPath (String path) : Ok, this is missing too. Its 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.

Only relief is that XMLNode gives “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 api’s. But again, every wrapper is apex and every line apex line you write will add to script limits. But the fact that hurts me 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 an web service call and its supposed to go inside a big xml parent node. I would say salesforce API team should at least consult existing XmlDom class for its intuitive design and ease to use.

Apart from that the API and its docs both are confusing. There are two methods in Dom.XmlNode

  • String getAttribute(String key, String keyNamespace)
  • String getAttributeValue(String key, String keyNamespace)

Apex docs for both of these is same : “Returns the attribute value for the given key and keyNamespace.” So why the hell there are two APIs that do same thing, receive same arguments and return same type. Here is the link for Apex docs. For quick look here is the screenshot.

image

Now I felt the real pain, when I started porting a XMLDom based apex code to Dom.Document/XmlNode. I will not say anything, 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.

image

I still love the simple design of XmlDom.cls, and wish salesforce can create a replica of that instead 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 starting I was pretty excited about this new Spring 10 API, but the excitement ended soon when I started using it. Its really a pain to use and worst design Apex API for me.