The other day there was a post on LinkedIn regarding importing Excel data into Notes documents.
Someone suggested to save into Access format, and then export from there intosome 1-2-3formatthat Notes can read.
I suggested to save the Excel spreadsheet as a CSV file, and then import it. So I decided to write a small generic importer.
I built a class called “csvFile”, which I put in a script library called “Class.ImportCSV”.
Below is the code for the actual import agent. It creates a new csvFile object, which load all the CSV data into an array in memory. Each array element is in turn a class, containing a list of entries. This is because you can not create arrays of arrays or lists, they have to be in another object/class.
If you know the row number and column label (the first row in the CSV file will be considered the column labels), you can address the value like this: csvfile.row(r).entry(“ColumnLabel”).
Option Public Option Declare Use "Class.ImportCSV" Sub Initialize ' *** Import CSV file and create matching documents in Notes ' *** By Karl-Henry Martinsson, April 8, 2010 Dim session As New NotesSession Dim db As NotesDatabase Dim doc As NotesDocument Dim csvfile As csvFile Dim rowcnt As Long Dim r As Long Set db = session.CurrentDatabase Set csvfile = New csvFile("c:\Book1.csv") rowcnt = Ubound(csvfile.row) + 1 ' *** Loop through the rows and create a new document for each For r = Lbound(csvfile.row) To Ubound(csvfile.row) If (r+1 Mod 10) = 0 Then ' Update status bar every 10 documents Print "Importing " & r+1 & " of " & rowcnt End If Set doc = New NotesDocument(db) Call doc.ReplaceItemValue("Form", "MyFormName") ' *** Loop though entries for the row and populate corresponding fields in doc Forall e In csvfile.row(r).entry Call doc.ReplaceItemValue(Listtag(e), e) End Forall Call doc.Save(True,False) Next End Sub
Here is the script library. Simply create a new script library, call it “Class.ImportCSV” and paste the code into it’s Declaration section:
' *** Created by Karl-Henry Martinsson on 2010-04-08 ' *** Email: TexasSwede@gmail.com ' *** Blog: http://blog.texasswede.com ' *** ---------------------------------------------------------- ' *** You are free to modify and edit this code, but please keep ' *** all comments intact, and publish any changes you make so ' *** the Lotus community can benefit. You are allowed to use ' *** this code in commercial/closed source products, but are ' *** encouraged to share your modifications. ' *** Disclaimer: Use this code at your own risk. No warranties ' *** what so ever. Don't run code you don't know what it does. ' *** ---------------------------------------------------------- Class RowData Public entry List As String End Class Class csvFile Public row() As RowData ' Storing the rows in the imported CSV file Public column List As String ' List containing column labels Private fileno As Integer ' File number Public Sub new(filename As String) Dim temprow As String Dim temparr As Variant Dim fixedarr() As String Dim i As Integer Dim flagQuoted As Integer fileno = Freefile ' Return an unused file number Open filename For Input As fileno Redim row(0) As rowdata ' *** Get column header Do While Not Eof(fileno) ' *** Read row and split into cells. Line Input #fileno, temprow temparr = Split(temprow, ",") ' *** Commas within quoted values will cause the value ' *** to be split across array items, so we have to fix this. flagQuoted = False Redim fixedarr(0) As String ' Size array to just one element, has to be done For i = Lbound(temparr) To Ubound(temparr) ' *** Check if value start with quote If Left$(temparr(i),1) = |"| Then flagQuoted = True End If If flagQuoted = True Then If Left$(temparr(i),1) = |"| Then ' *** For first item, just set array item to value, remove leading quote fixedarr(Ubound(fixedarr)) = Right$(temparr(i),Len(temparr(i))-1) Else ' *** Append value to previous array item with a comma to replace the lost one fixedarr(Ubound(fixedarr)) = fixedarr(Ubound(fixedarr)) & "," & temparr(i) End If ' *** If it end with a quote, reset flag, rmove trailing quote and increase size of array If Right$(temparr(i),1) = |"| Then flagQuoted = False fixedarr(Ubound(fixedarr)) = Left$(fixedarr(Ubound(fixedarr)), Len(fixedarr(Ubound(fixedarr)))-1) Redim Preserve fixedarr(Ubound(fixedarr)+1) As String End If Else ' *** Set array item to value and increase array size by one fixedarr(Ubound(fixedarr)) = temparr(i) Redim Preserve fixedarr(Ubound(fixedarr)+1) As String End If Next temparr = Fulltrim(fixedarr) ' Remove empty items in array ' *** Check if this is the first row (index 0), i.e. the column header and no object exists If Ubound(row) = 0 And (row(Ubound(row)) Is Nothing) Then ' *** Loop through temparr and build list from labels For i = Lbound(temparr) To Ubound(temparr) column(Cstr(i)) = temparr(i) Next ' *** Create an object so the code above will not be true again Set row(Ubound(row)) = New RowData Else ' *** Create new row data object, populate with data and increase size of row array Set row(Ubound(row)) = New RowData For i = Lbound(temparr) To Ubound(temparr) row(Ubound(row)).entry(column(Cstr(i))) = temparr(i) Next Redim Preserve row(Ubound(row)+1) As RowData End If Loop ' *** Remove the last row, as it is always empty Redim Preserve row(Ubound(row)-1) As RowData End Sub End Class
Halo, many thanks for that cool script. Do you have any trick how to import more than 32767 lines? David
From the online help:
“Array subscript bounds must fall in the range -32,768 to 32,767, inclusive.”
I never tried it, but try to change
Redim row(0) As rowdata
to
Redim row(-32768) As rowdata
i = -32768
and see what happens. Should double the number or lines you can import. If you have more than 64K lines, you could perhaps try rewriting the code using a list instead of an array.
This saved my day. thank you. This code will fail if any row (other than first row which is header) has empty value
temparr = Fulltrim(fixedarr) ‘ Remove empty items in array this line of code actually removes empty values in array which seems to be not right. it is ok to remove empty items for the first row but not subsequent rows
Thank you for sharing this valuable utility. After successfully using it for English format .csv (uses a comma as the delimiter), I created a version for European format which uses the semicolon as the delimiter.
I also added the following code to prompt the user to select the .csv file
‘Get .csv file name
If userPlatform = “Macintosh/64” Or userPlatform = “Macintosh” Then
fn=uiws.OpenFileDialog(False, “Select the .csv File to Import”)
Else
fn =uiws.OpenFileDialog(False,”Select the .csv File to Import”, “.csv files | *.csv”, “c:My Documents”)
End If
csvFilename = Cstr(fn(0)) ‘ This is the name of the .csv file that will be imported
If Lcase(Right(csvFilename, 3)) “csv” Then
mb = uiws.Prompt(1, “Please select a file with a .csv extension.”, “Wrong file type. A .csv file extension is expected”)
Else
Set csvfile = New EUcsvFile(csvFilename)
rowcnt = Ubound(csvfile.eurow) + 1
I also added code to coerce the values being set in the target document (doc) to the correct data type. The If statement in the code first checks if the entry is one of your text fields (you supply the name … I just used “TextField1”, “TextField2”, “TextField3”, “TextField4”, and “TextFieldn” as generic field names to illustrate the code. If the entry is not one of your text fields, then the code checks to see if it is one of your Integer fields … in this example I just check for one and generically named it “IntegerField1”. If the entry is not one of your text or integer fields, then this code makes it a Dbl.
‘ *** Loop though entries for the row and populate corresponding fields in doc
Forall e In csvfile.row(r).entry
If Listtag(e) = “TextField1” Or Listtag(e) = “TextField2” Or Listtag(e) = “TextField3” Or Listtag(e) = “TextField4” Or Listtag(e) = “TextFieldn” Then
Call doc.ReplaceItemValue(Listtag(e), e)
Elseif Listtag(e) = “IntegerField1” Then
Call doc.ReplaceItemValue(Listtag(e), Cint(e))
Else
Call doc.ReplaceItemValue(Listtag(e), Round(Cdbl(e),8))
End If
End Forall