I have developed an Inbound webservice .Where i receive an xml which contains multiple records.I'm wondering where i'm missing the bulk records. My code works fine for one record but fails to handle multiple records. here is the code

/* GAP 7 */

global with sharing class CreditGap7 {
    webservice static string UpdateAccounts(string xml){
        Savepoint sp = Database.setSavepoint( );
        List<CreditRecords> deb = new List<CreditRecords>();
        set<Id>accid = new set<Id>();
        // Map<Id,ERP_Customer_Record__c> erpmap = new Map<Id,ERP_Customer_Record__c>();
        //CreditRecords deb1 ;
        string creditRecordsId;
        List<ERP_Customer_Record__c> updErp = new List<ERP_Customer_Record__c>();
        String Status;
        list<Advanced_Log__c> ad = new list<Advanced_Log__c>();
        //  set<Id> updErps = new set<Id>(); // to store updErp

        System.debug('The Xml data is:'+xml);
        /*xml =  <xml><DebtorNavCreditMsg><SFDCAccountId>001L000000cWq8IIAS</SFDCAccountId><CreditStatus>Blocked</CreditStatus><PaymentTerms> 12 </PaymentTerms>
<CreditLimit>123.2</CreditLimit><DebtorId>C23456767</DebtorId><Status>Sucess </Status><Skey>11  </Skey>
<CreditStatus>Blocked</CreditStatus><PaymentTerms> 12 </PaymentTerms><CreditLimit>123.2</CreditLimit><DebtorId>C23456767</DebtorId><Status>Sucess </Status><Skey>11  </Skey>

        //Creating Advanced log record with received xml string
        Advanced_Log__c log = new Advanced_Log__c( );
        log.Received_Data_Stream__c = xml != null && xml != '' ? xml : 'XML is empty.';
        log.Log_Type__c = 'System';
        log.Process_Name__c = 'GAP7';
        log.Status__c = 'New';
        log.User_Id__c = UserInfo.getUserId( );
        // insert log;

            if ( xml == null || xml == '' )
                return 'XML is empty.';
            XMLParser( addCDataNodes(xml), deb );
            for(CreditRecords s : deb) // Sindoora  
                if(s.SFDCAccountId != null || s.SFDCAccountId != '')
                    System.debug('The SFDC Account is'+s.SFDCAccountId);

                    //System.debug('The Ids are'+accid);
                    **for(ERP_Customer_Record__c debRecords : [select Id,Account__c,Credit_Status__c,Payment_Terms__c,Credit_Limit__c from ERP_Customer_Record__c where  Account__r.Id =:s.SFDCAccountId])**
                        System.debug('The ERP Record is:'+debRecords.Id);
                        ERP_Customer_Record__c creditrecord = debRecords;
                        log.ERPAccountId__c = creditrecord.Id ;// This stores Bridge object Id
                        creditRecordsId = creditrecord.Id;
                        creditrecord = new  ERP_Customer_Record__c(Id = creditRecordsId,Account__c = s.SFDCAccountId,Credit_Status__c = s.CreditStatus,Payment_Terms__c = s.PaymentTerms,Credit_Limit__c = s.CreditLimit != '' ? decimal.valueOf( s.CreditLimit.trim() ) : null ,CreditLastModified__c = system.now()); 
                        updErp.add(creditrecord); // Bridge Object
                        ad.add(log); //Advanced Log
                        Status = Status + '<DebtorNavCreditMsg><Key>'+s.SKey+'</Key><SFDCAccountID>'+s.SFDCAccountId+'</SFDCAccountID><Status>Sucess</Status>'+
                            '<Message>The records are inserted sucessfully</Message> </DebtorNavCreditMsg>';
                        System.Debug('The status is:'+Status);

                else if( s.SFDCAccountId == '' || s.SFDCAccountId == null )// Id is empty  throwing error.
                    log.Log_Message__c = +s.SFDCAccountId + ' SFDCAccountID is required.';
                    log.Log_Level__c = 'Error';
                    Status = Status + '<DebtorNavCreditMsg><Key>'+s.SKey+'</Key><SFDCAccountID>'+s.SFDCAccountId+'</SFDCAccountID><Status>Failure</Status>'+
                        '<Message>The SFDC Record Id is Missing</Message> </DebtorNavCreditMsg>';

            update updERP;
            insert ad;
            return Status;
            //System.debug('The String is:'+Status);


        catch( Exception ex )
            Database.rollback( sp );//If any error occured rollback all transactions from DB
            // Advanced_Log__c log = new Advanced_Log__c( );

            log.ERPAccountId__c = creditRecordsId;
            log.Log_Message__c = 'Exception';
            log.Log_Message__c = ex.getMessage( ).length() > 200? creditRecordsId +' Exception: ' + ex.getMessage().substring(0,200):creditRecordsId + ' Exception: ' +ex.getMessage( );
            log.Log_Level__c = 'Error';
            insert log;//creating log record with exception message

            return '<SFDCAccountID>' + creditRecordsId + '</SFDCRecordID><Status>Failure</Status>'+
                '<Message>Exception:' + ex.getMessage() + '</Message>';



    //This method parse the string and create the wrapper class object
    private static String addCDataNodes( String XmlString )
        Pattern CDataSectionPattern = Pattern.compile('<!\\[CDATA\\[(.*?)\\]\\]>');
        Matcher m = CDataSectionPattern.matcher(XmlString);
        while (m.find())    
            XmlString = XmlString.substring(0, m.start()) +
                m.group(1).escapeXml() +
                +  XmlString.substring( m.end());
            m = CDataSectionPattern.matcher(XmlString);
            System.debug('The XMLString is:'+XmlString);
        return XmlString;

    // XMLParser Method  
    private static void XMLParser( string xml, CreditRecords[] deb )
        CreditRecords deb1;

        Dom.Document doc = new Dom.Document();
        doc.load( xml );

        Dom.XMLNode DebtorNavCreditMsg = doc.getRootElement();
        for( Dom.XMLNode child1 : DebtorNavCreditMsg.getChildElements( ) )//looping all the child nodes from xml
            deb1 = new CreditRecords();
            String test = child1.getName();
            System.debug('test child:'+Test);
            for( Dom.XMLNode child : child1.getChildElements( ) ) 
                string Text = child.getName();
                System.debug('The node is :'+Text);

                if(Text == 'SFDCAccountID') 
                    deb1.SFDCAccountID = child.getText();
                if(Text == 'CreditStatus')  
                    deb1.CreditStatus = child.getText();
                if(Text == 'PaymentTerms')
                    deb1.PaymentTerms = child.getText();
                if(Text == 'CreditLimit')
                    deb1.CreditLimit = child.getText();
                if(Text == 'SKey')
                    deb1.SKey = child.getText();



    //Wrapper class 
    public class CreditRecords
        public string CreditStatus{get;set;}
        public string SFDCAccountID{get;set;}
        public string PaymentTerms{get;set;}
        public string CreditLimit{get;set;}
        public string SKey{get;set;}
        public string Status{get;set;}


Your code is processing the first record it comes across and then it uses return to return a value, which by the way, is not even valid XML, as it has no root node, and may contain unescaped XML characters. You should instead create classes to process the XML correctly. For example, instead of accepting a string, accept a DebtorNavCreditMsg instead:

global class DebtorNavCreditMsg {
    global String SFDCAccountId, CreditStatus, DebtorId, Status, Skey;
    global Integer PaymentTerms;
    global Decimal CreditLimit;
global class DebtorNavCreditMsgResult {
    global String SFDCAccountId, CreditStatus, DebtorId, Status, Skey, Message;
    global Integer PaymentTerms;
    global Decimal CreditLimit;

webservice static DebtorNavCreditMsgResult[] UpdateAccounts(DebtorNavCreditMsg[] params){

Next, make sure you're you're only using return at the end of your method; aggregate together all of the processing and return one result.

webservice static DebtorNavCreditMsgResult[] UpdateAccounts(DebtorNavCreditMsg[] params){
    DebtorNavCreditMsgResult[] results = new DebtorNavCreditMsgResult[0];
    for(DebtorNavCreditMsg param: params) {
        // Process each record individually
    return results;

You may also want/need to bulkify your code if you're expecting a large number of updates per call, possibly including Database.update(records, false) to allow partial success. This really depends on if you want to allow some records to update even if others error, which is probably ideal, but requires more logic on the client.

The benefit of writing your code this way is that you'll be able to download a WSDL and get tight data binding with your webservice method, instead of the much more challenging XML processing you're doing here. Note that the code I wrote above is automatically handling the XML serialization and deserialization. The WSDL approach makes it easier to write clients that will be easier to debug when things go wrong.

| improve this answer | |
  • As my xml contains CDATA i followed doc procedure. Here is my updated code. – Sindoora Jul 17 '17 at 12:09
  • The query doesn't fetch any records not sure the reason(highlited in bold). I have crossed check and the records do exsit – Sindoora Jul 17 '17 at 12:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.