2012-05-03 47 views
1

我有一個CSV,其中包含需要轉到多個Salesforce自定義對象的字段。我創建了APEX類來處理解析。然而,當我打電話從VisualForce頁面類,我收到消息:如何在Salesforce中解析CSV

Collection size 3,511 exceeds maximum size of 1,000. 

我APEX類如下(從2篇博客文章拼湊起來的話題):

public class parseCSV{ 
public Blob contentFile { get; set; }  
public String nameFile { get; set; }  
public Integer rowCount { get; set; }  
public Integer colCount { get; set; }  
public List<List<String>> getResults() {   
List<List<String>> parsedCSV = new List<List<String>>();   
rowCount = 0;   
colCount = 0;   
if (contentFile != null){    
String fileString = contentFile.toString();    
parsedCSV = parseCSV(fileString, false);    
rowCount = parsedCSV.size();    
for (List<String> row : parsedCSV){     
if (row.size() > colCount){      
colCount = row.size();     
}    
}   
}   
return parsedCSV;  
} 
public static List<List<String>> parseCSV(String contents,Boolean skipHeaders) {   
List<List<String>> allFields = new List<List<String>>();  
// replace instances where a double quote begins a field containing a comma  
// in this case you get a double quote followed by a doubled double quote  
// do this for beginning and end of a field  
contents = contents.replaceAll(',"""',',"DBLQT').replaceall('""",','DBLQT",');  
// now replace all remaining double quotes - we do this so that we can reconstruct  
// fields with commas inside assuming they begin and end with a double quote  
contents = contents.replaceAll('""','DBLQT');  
// we are not attempting to handle fields with a newline inside of them  
// so, split on newline to get the spreadsheet rows  
List<String> lines = new List<String>();  
try {   
lines = contents.split('\n');  
} 
catch (System.ListException e) {   
System.debug('Limits exceeded?' + e.getMessage());  
}  
Integer num = 0;  
for(String line : lines) {   
// check for blank CSV lines (only commas)   
if (line.replaceAll(',','').trim().length() == 0) break; 
List<String> fields = line.split(',');   
List<String> cleanFields = new List<String>();   
String compositeField;   
Boolean makeCompositeField = false;   
for(String field : fields) {    
if (field.startsWith('"') && field.endsWith('"')) 
{ 
      cleanFields.add(field.replaceAll('DBLQT','"'));    
} 
else if (field.startsWith('"')) {     
makeCompositeField = true;     
compositeField = field;    
} 
else if (field.endsWith('"')) { 
compositeField += ',' + field;     
cleanFields.add(compositeField.replaceAll('DBLQT','"'));     
makeCompositeField = false;    
} 
else if (makeCompositeField) {     
compositeField += ',' + field;    
} 
else { 
cleanFields.add(field.replaceAll('DBLQT','"'));    
}   
}     
allFields.add(cleanFields);  
}  
if (skipHeaders) allFields.remove(0);  
return allFields;  
} 
} 

如何我確保上面的類將正確的列從CSV插入正確的自定義對象嗎?

由於一些對象包含其他人的查詢,我如何確保數據首先加載到查找字段中,然後再加載到子表中?

最後,我如何解決上述錯誤消息?除了建議使用VisualForce頁面之外還有其他的東西嗎?

非常感謝您的幫助和指導。

+0

您是如何進行測試的? – Red2678

+0

這裏有太多獨立的問題(「我如何解析CSV?」,「我該如何解決這段特殊的代碼?」,「我應該使用VisualForce頁面以外的東西嗎?」,「我該如何解決這個特定的錯誤?「)讓任何人以對未來讀者有用的方式全面回答。 :( –

回答

5

出於興趣,這是否需要從visualforce頁面?您可以使用Data Loader加載CSV,或者使用批量API自行構建解決方案。

如果您確實需要從頁面做到這一點,我建議,而不是立即就新線分割的,可以使用substringindexOf從輸入字符串一次只拉一條線,他們處理當你去時。

+0

我避免使用Data Loader,因爲CSV包含的字段需要插入到單獨的對象中,而不是一個對象中。例如,CSV包含要加載到Calls中的CallFrom和CallTo字段對象,這些對另一個表DID進行查找,因此,爲了使CallFrom和CallTo成功加載到Call對象中,必須有DID中的條目,DataLoader是否可以處理這種用例? – SidC

+1

不是一回事 - 這是一個常規的加載或偶爾的?如果偶爾我會建議使用dataloader進行加載,並使用VLOOKUP的第一個加載成功文件來設置查找ID在其他表中。如果它是一個常規的東西,那麼也許你'd最好找一個ETL工具來使用嗎? –

+0

聽起來像一個ETL工具是最好的選擇,因爲會有這種性質的例行上傳。除了SSIS,你是否建議其他人在這個spa做得很好CE? – SidC

1

我試圖處理一個4MB的CSV文件,並且SalesForce返回給我一個「Regext too too」錯誤。我相信這個問題與你的問題類似。

我使用批量頂點和迭代器修復了它。進一步的信息在this link

1

salesforce的這個例子並不處理你自己有單引號的情況。

例如,

",",XXX,YYY 

這將返回4場時,只有3

的問題是:

if (field.startsWith('"') && field.endsWith('"')) 

當你有一個領域,如:

" 

它既開始與雙引號結束,但事實並非測試

其更改爲的意圖:

if (field.length() > 1 && field.startsWith('"') && field.endsWith('"')) { 

,它會工作。

完整校正的例子是:

public class parseCSV{ 
public Blob contentFile { get; set; }  
public String nameFile { get; set; }  
public Integer rowCount { get; set; }  
public Integer colCount { get; set; }  
public List<List<String>> getResults() {   
List<List<String>> parsedCSV = new List<List<String>>();   
rowCount = 0;   
colCount = 0;   
if (contentFile != null){    
String fileString = contentFile.toString();    
parsedCSV = parseCSV(fileString, false);    
rowCount = parsedCSV.size();    
for (List<String> row : parsedCSV){     
if (row.size() > colCount){      
colCount = row.size();     
}    
}   
}   
return parsedCSV;  
} 
public static List<List<String>> parseCSV(String contents,Boolean skipHeaders) {   
List<List<String>> allFields = new List<List<String>>();  
// replace instances where a double quote begins a field containing a comma  
// in this case you get a double quote followed by a doubled double quote  
// do this for beginning and end of a field  
contents = contents.replaceAll(',"""',',"DBLQT').replaceall('""",','DBLQT",');  
// now replace all remaining double quotes - we do this so that we can reconstruct  
// fields with commas inside assuming they begin and end with a double quote  
contents = contents.replaceAll('""','DBLQT');  
// we are not attempting to handle fields with a newline inside of them  
// so, split on newline to get the spreadsheet rows  
List<String> lines = new List<String>();  
try {   
lines = contents.split('\n');  
} 
catch (System.ListException e) {   
System.debug('Limits exceeded?' + e.getMessage());  
}  
Integer num = 0;  
for(String line : lines) {   
// check for blank CSV lines (only commas)   
if (line.replaceAll(',','').trim().length() == 0) break; 
List<String> fields = line.split(',');   
List<String> cleanFields = new List<String>();   
String compositeField;   
Boolean makeCompositeField = false;   
for(String field : fields) {    
if (field.length() > 1 && field.startsWith('"') && field.endsWith('"')) { 
{ 
      cleanFields.add(field.replaceAll('DBLQT','"'));    
} 
else if (field.startsWith('"')) {     
makeCompositeField = true;     
compositeField = field;    
} 
else if (field.endsWith('"')) { 
compositeField += ',' + field;     
cleanFields.add(compositeField.replaceAll('DBLQT','"'));     
makeCompositeField = false;    
} 
else if (makeCompositeField) {     
compositeField += ',' + field;    
} 
else { 
cleanFields.add(field.replaceAll('DBLQT','"'));    
}   
}     
allFields.add(cleanFields);  
}  
if (skipHeaders) allFields.remove(0);  
return allFields;  
} 
} 
+0

當前的代碼沒有考慮用引號括起來的字段(以「我的數據」爲例)。爲了解決這個問題,你需要做的就是把if(field.endsWith('''))塊放在if(field.startsWith('''))塊的前面。此代碼在逗號後最後也沒有考慮空白數據。例如,字符串「one,two,three」將計爲3列,而不是4.要解決該問題,請將line.spit(',')更改爲line.split(',',-1)。這段代碼在大字符串上仍然會產生問題,導致contents.split()和contents.replaceAll()引發'RegEx too too'錯誤。 –

+0

要使這項工作適用於大型文件,請將contents.replaceAll()移至一行。replaceAll()並用一個函數替換contents.split('\ n'),該函數使用Matcher類,該類可以提前區域化並在X次匹配後重置。 –

1

我已經收到該消息太當我試圖轉換CSV數據(1000記錄)存儲成一個列表以顯示一個Visualforce頁面上。如果你要顯示導入的記錄(這是一個很好的功能),你需要確保你顯示的列表少於1000個元素。

要插入記錄到Salesforce的對象,做這樣的事情:

我定義了一個名爲「的Util」有一個名爲「parseCSV」靜態方法類(見下文):

public blob importedCSV {get;set;} 

list<list<string>> parsedCSV = Util.parseCSV(importedCSV.toString(),true); 
list<Custom_Object__c> cObjsToInsert = new list<Custom_Object__c>(); 
for(list<string> line:parsedCSV){ 
    Custom_Object__c c = new Custom_Object__c(); 
    c.Name=line[0]; 
    c.String_Field__c=line[2]; 
    c.Currency_Field__c=decimal.valueof(line[3]); 
    if(line.size()>4) 
     c.Description__c=line[4]; 
    cObjsToInsert.add(c); 
} 
insert cObjsToInsert; 

通常,當我處理CSV並將數據插入Salesforce對象時,我不會遇到大小錯誤。我製作了導入CSV的Visualforce頁面,以某種奇特的方式處理CSV,然後將處理後的數據導出爲CSV,Excel或文本(固定寬度)格式。我將在Visualforce頁面上加載CSV並將數據作爲附件保存在虛擬記錄中。然後,我會將用戶導向另一個抓取附件,處理數據並輸出爲所需格式的Visualforce頁面。

我不記得我在哪裏得到這段代碼,但它像一個魅力。我也爲parseCSV方法寫了測試代碼

public static list<list<String>> parseCSV(String contents,Boolean skipHeaders) { 
    list<list<String>> allFields = new List<List<String>>(); 

    // replace instances where a double quote begins a field containing a comma 
    // in this case you get a double quote followed by a doubled double quote 
    // do this for beginning and end of a field 
    contents = contents.replaceAll(',"""',',"DBLQT').replaceall('""",','DBLQT",'); 
    // now replace all remaining double quotes - we do this so that we can reconstruct 
    // fields with commas inside assuming they begin and end with a double quote 
    contents = contents.replaceAll('""','DBLQT'); 
    // we are not attempting to handle fields with a newline inside of them 
    // so, split on newline to get the spreadsheet rows 
    list<String> lines=new list<string>(); 
    try { 
     lines = contents.split('\n'); 
    } catch (System.ListException e) { 
     System.debug('Limits exceeded? '+e.getMessage()); 
    } 
    integer num=0; 
    for(string line :lines) { 
     // check for blank CSV lines (only commas) 
     if(line.replaceAll(',','').trim().length()==0) 
      break; 
     list<String> fields=line.split(',');  
     list<String> cleanFields=new list<String>(); 
     string compositeField; 
     boolean makeCompositeField=false; 
     for(string field : fields) { 
      if(field.startsWith('"') && field.endsWith('"')) { 
       cleanFields.add(field.replaceAll('DBLQT','"').removeStart('"').removeEnd('"')); 
      } else if(field.startsWith('"')) { 
       makeCompositeField = true; 
       compositeField = field; 
      } else if(field.endsWith('"')) { 
       compositeField += ',' + field; 
       cleanFields.add(compositeField.replaceAll('DBLQT','"').removeStart('"').removeEnd('"')); 
       makeCompositeField = false; 
      } else if(makeCompositeField) { 
       compositeField += ',' + field; 
      } else{ 
       cleanFields.add(field.replaceAll('DBLQT','"').removeStart('"').removeEnd('"')); 
      } 
     } 
     allFields.add(cleanFields); 
    } 
    if(skipHeaders) 
     allFields.remove(0); 
    return allFields;  
}//END ParseCSV 

@isTest 
private static void testParseCSV(){ 
    string contents='Field1,Field2,Field3\n1,,Smith\n2,Fred,O\'Connor\n3,Destiny,"Awaits, DDS"\n\n'; 
    list<list<string>> parsedCSV=Util.parseCSV(contents,true); 
    //line 1 
    system.assertEquals('1',parsedCSV[0][0]); 
    system.assertEquals('',parsedCSV[0][1]); 
    system.assertEquals('Smith',parsedCSV[0][2]); 
    //line 2 
    system.assertEquals('2',parsedCSV[1][0]); 
    system.assertEquals('Fred',parsedCSV[1][1]); 
    system.assertEquals('O\'Connor',parsedCSV[1][2]); 
    //line 3 
    system.assertEquals('3',parsedCSV[2][0]); 
    system.assertEquals('Destiny',parsedCSV[2][1]); 
    system.assertEquals('Awaits, DDS',parsedCSV[2][2]); 
}//END 

我把這段代碼放在一個名爲「Util」的類中。如果你有一個blob,首先將它轉換爲一個字符串,然後調用該方法。例如

blob b=inputBlob; 
list<list<string>> parsedCSV = Util.parseCSV(b.toString(),true);