function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Sindhu1234Sindhu1234 

How to handle multiple records in xml for inbound webservice

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( );
        CreditRecords deb = new CreditRecords( );
        string creditRecordsId;
        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>
                      
             </DebtorNavCreditMsg>
<DebtorNavCreditMsg><SFDCAccountId>001L000000cWq8IIAS</SFDCAccountId>
                      <CreditStatus>Blocked</CreditStatus>
                      <PaymentTerms> 12 </PaymentTerms>
                      <CreditLimit>123.2</CreditLimit>
                      <DebtorId>6767</DebtorId>
                      <Status>Sucess </Status>
                        <Skey>113  </Skey>
                      
             </DebtorNavCreditMsg> */ 
        
  
   Advanced_Log__c log = new Advanced_Log__c( );//Creating Advanced log record with received xml string
        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( );
  
  try
        {
           
            if ( xml == null || xml == '' )
                return 'XML is empty.';
            
             XMLParser( addCDataNodes(xml), deb );
           // System.debug('The Pharsed deb xml is:'+deb);
            if ( deb.SFDCAccountId == ''  )// Id is empty  throwing error.
             {
                log.Log_Message__c = ' SFDCAccountID is required.';
                log.Log_Level__c = 'Error';
                insert log;
                
                return '<SFDCAccountID>' +deb.SFDCAccountId+ '</SFDCAccountID><CreditStatus>' +deb.CreditStatus + '</CreditStatus>'+
                      '<PaymentTerms> '+deb.PaymentTerms+' </PaymentTerms><CreditLimit>'+deb.CreditLimit+'</CreditLimit><Status>Failure</Status>'+
                    '<Message>DebtorNavCreditMsg.SFDCAccountID is empty</Message>';
             }
             List<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__c=:deb.SFDCAccountID];
            System.debug('The deb record is:'+debRecords); 
            if ( !debRecords.isEmpty( ) && debRecords.size() > 0 )
                {
                    ERP_Customer_Record__c creditRecords = debRecords[ 0 ];
                    log.ERPAccountId__c = creditRecords.Id;
                   creditRecordsId  = creditRecords.Id;
                    //Replace CustomerCreditCheck with the tag provided by LX
                    creditRecords = new ERP_Customer_Record__c( Id = creditRecordsId,Account__c = deb.SFDCAccountId,Credit_Status__c = deb.CreditStatus,Payment_Terms__c = deb.PaymentTerms,Credit_Limit__c = deb.CreditLimit != '' ? decimal.valueOf( deb.CreditLimit.trim() ) : null ,CreditLastModified__c = system.now());
                    update creditRecords;
                    
                     log.Log_Message__c = deb.SFDCAccountId + ' (' + creditRecordsId + ') updated successfully.';
                    log.Log_Level__c = 'Info';
                    insert log;//creating log record
                    
                    return '<SFDCAccountID>' + creditRecordsId + '</SFDCAccountID><Status>Success</Status>'+
                            '<Message>' + deb.SFDCAccountId + ' (' + creditRecordsId+ ') +updated successfully</Message>';
                }
                
                 else
              {
                log.Log_Message__c = 'The AccountId is needed to update the debCustomerRecords.';
                log.Log_Level__c = 'Notification';
                insert log;//creating log record
                
                return '<SFDCAccountID>' + creditRecordsId + '</SFDCAccountID><Status>Notification</Status>'+
                        '<Message>The AccountId is needed to update the debCustomerRecords.</Message>';
              }
        }
      catch( Exception ex )
        {
            Database.rollback( sp );//If any error occured rollback all transactions from DB
            
            log.ERPAccountId__c = creditRecordsId;
            log.Log_Message__c = ex.getMessage( ).length() > 200? deb.SFDCAccountId +' Exception: ' + ex.getMessage().substring(0,200):deb.SFDCAccountId + ' 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(ItemRecord)
    private static String addCDataNodes( String XmlString )
    {
        Pattern CDataSectionPattern = Pattern.compile('<!\\[CDATA\\[(.*?)\\]\\]>');
        Matcher m = CDataSectionPattern.matcher(XmlString);
        while (m.find())    //could be simplified with a replaceAll ? @todo
        {
            XmlString = XmlString.substring(0, m.start()) +
                '<CDataSection>'+
                m.group(1).escapeXml() +
                '</CDataSection>'
                +  XmlString.substring( m.end());
            m = CDataSectionPattern.matcher(XmlString);
        }
        return XmlString;
        
    }
    
    private static void XMLParser( string xml, CreditRecords deb )
    {
       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
        {
           // String Text1 = child1.getName();
            
            
            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') 
            deb.SFDCAccountID = child.getText();
            if(Text == 'CreditStatus')  
            deb.CreditStatus = child.getText();
            if(Text == 'PaymentTerms')
            deb.PaymentTerms = child.getText();
            if(Text == 'CreditLimit')
            deb.CreditLimit = child.getText();
            
           }
            }
       
    }
    //Wrapper class for ItemMaster
    public class CreditRecords
    {
        public string CreditStatus{get;set;}
         public string SFDCAccountID{get;set;}
        public string PaymentTerms{get;set;}
        public string CreditLimit{get;set;}
       
    }       
             
  

}
NagendraNagendra (Salesforce Developers) 
Hi Sindhu,

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.

Hope this helps.

Please mark this as solved if it's resolved so that it gets removed from the unanswered queue which results in helping others who are encountering a similar issue.

Thanks,
Nagendra