[SalesForce] How to Reorder XML tags

In the below code –> mapcolRows.put(subchildelement.getName(),subchildelement.getText()); subchildelement.getName() gets 'Enabled' and 'Name' tags in XML as shown below

<Profile xmlns="http://soap.sforce.com/2006/04/metadata">
<custom>true</custom>
<userLicense>Salesforce</userLicense>
<userPermissions>
    <enabled>true</enabled>
    <name>AllowViewKnowledge</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>ApiEnabled</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>ChatterForSharePoint</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>ChatterInternalUser</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>ChatterInviteExternalUsers</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>ChatterOwnGroups</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>ConvertLeads</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>CreateCustomizeFilters</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>CreateCustomizeReports</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>CreateTopics</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>DistributeFromPersWksp</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>EditEvent</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>EditOppLineItemUnitPrice</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>EditTask</name>
</userPermissions>
<userPermissions>
    <enabled>true</enabled>
    <name>EditTopics</name>
</userPermissions>

Image shows the out of XML

I would like to achieve 'name' tag first and 'enabled' tag below 'name' tag as shown

<userPermissions>
 <name>AllowViewKnowledge</name>    
 <enabled>true</enabled>

 for(Dom.XmlNode subchildelement:childlist[0].getChildElements())
 {
      System.debug('------------------1subchildelement : ' + subchildelement);
      subChildElementName = subchildelement.getName();
      System.debug('------------------2subChildElementName : ' + subChildElementName);
      subChildElementsList.add(subChildElementName);
      elementValues = subchildelement.getText();
      System.debug('------------------3elementValues ' + elementValues); 
      elementValuesList.add(elementValues);
 }

 for(Dom.XmlNode childelement : rootElement.getChildElements())    
 {    
      System.debug('------------------11childelement : ' + childelement);
      mapcolRows = new map<String,String>();
      System.debug('------------------22mapcolRows : ' + mapcolRows);
      for (Dom.XmlNode subchildelement:childelement.getChildElements())
      {
           System.debug('------------------33subchildelement getName: ' + subchildelement.getName());
           System.debug('------------------333subchildelement getText: ' + subchildelement.getText());
           mapcolRows.put(subchildelement.getName(),subchildelement.getText());
           //mapcolRows.put(subchildelement.getText(),subchildelement.getName());
           System.debug('------------------44mapcolRows : ' + mapcolRows);
      }

      rowValues.add(mapcolRows);  //Add rowValuds list to here
      System.debug('------------------55rowValues : ' + rowValues);
      ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO,'Response is :' + rowValues));

 }

Once the order of XML tags is changed the output of the Table printing in Visualforce page should be as shown below

enter image description here

Best Answer

Trying to transform your xml, and then parsing it, is definitely the hard way of accomplishing this.

My preferred method of handling situations like this is to create an Apex class (with inner classes as appropriate) to recursively parse some given xml and, crucially, store the resulting data.

The idea is that if you have your data stored in a class instance, it doesn't matter what order the data is in because you can fetch data from a class in any order that you want.

The XML that you're working with is pretty simple. A partial example of a parsing/storage class for that XML is

public class Permissions{
    // 'Permission' is an inner class, which is defined below.
    // I find it helpful to have class names and variable names mirror the names used
    //   in the XML document as closely as possible.
    public List<Permission> userPermissions;

    public Permissions(String xmlInput){
        Dom.Document inputDoc = new Dom.Document();
        inputDoc.load(xmlInput);

        process(inputDoc.getRootElement());
    }

    // If you're going to use this in a visualforce page, you'll need to manually
    //   implement getter methods.
    public List<Permission> getUserPermissions(){
        return userPermissions;
    }

    // Each inner class will need a 'process' method like this one.
    private void process(Dom.XmlNode inNode){
        String currentNodeName;
        userPermissions = new List<Permission>();

        for(Dom.XmlNode childNode :inNode.getChildElements()){
            currentNodeName = childNode.getName();

            // When we come across a node that we want to handle, we simply create
            //   a new instance of the appropriate inner class, and pass the node
            //   to its process() method.
            // Each inner class should specialize in handling a specific type of XmlNode.
            // This helps to prevent the parsing logic from getting too unwieldy in 
            //   any one class.
            if(currentNodeName == 'userPermissions'){
                Permissions perm = new Permission();
                perm.process(inNode);

                // After we're done processing the current node, we can add it
                //   to the list.
                userPermissions.add(perm);
            }
        }
    }

    // When we get down to a level where a child element contains just a string,
    //   then there's little use in creating one more level of inner classes.
    // Such child elements can just be made variables of this class.
    public class Permission{
        // Again, variable names mirror those found in the XML document.
        public String name;
        public Boolean enabled;

        public Permission(){
        }

        // Again, getters are required for visualforce
        public Boolean getEnabled(){
            return enabled;
        }

        public String getName(){
            return name;
        }

        // This method should look like it has something in common with the 'process()'
        //   method of the outer class.
        // Having the same general structure makes this pattern easy to expand to
        //   be able to parse more complicated XML structures.
        public void process(Dom.XmlNode inNode){
            String currentNodeName;

            for(Dom.XmlNode childNode :inNode.getChildElements()){
                currentNodeName = childNode.getName();

                // Note: The order that you check currentNodeName values in doesn't matter at all
                if(currentNodeName == 'enabled'){
                    // For everything that isn't a string, we'll need to use the
                    //   appropriate 'valueOf()' method to convert to the correct type
                    enabled = Boolean.valueOf(childNode.getText());
                } else if (currentNodeName == 'name'){
                    // For strings, we don't need any special treatment
                    name = childNode.getText();
                }
            }
        }
    }
}

Yes, it's a bit more typing (~58 lines without the comments, compared to the 30 lines for your provided code), and it does get tedious for more complicated XML structures, but I believe that this approach makes up for that in flexibility, maintainability, readability, and extensibility.

Related Topic