I want to copy data from xml file to excel workbook
Every xml has got tag "Client name" but some of them also have got tag "Billing client name"
I want to achieve this with my code
If in xml tag "Billing client name" exists use it and ignore tag "Client name"
if in xml there is no tag "Billing client name" use data from tag "Client name"
My current code only paste data from tag "Client name"
My code:
Dim mainWorkBook As Workbook
Set mainWorkBook = ActiveWorkbook
mainWorkBook.Sheets("Sheet3").Activate
LR = Cells(Rows.Count, "A").End(xlUp).Row
'MsgBox LR
For x = 2 To LR
Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.SetProperty "SelectionLanguage", "XPath"
xmlDoc.Async = False
xmlDoc.Load ("\\path\" & Range("A" & x) & ".xml")
Set nodeXML = xmlDoc.getElementsByTagName("BILL_TO_CLIENTCODE")
Set nodeXML2 = xmlDoc.getElementsByTagName("CLIENTCODE")
If nodeXML Is Nothing Then
Range("B" & x).Value = nodeXML(i).Text
Else
Range("B" & x).Value = nodeXML2(i).Text
End If
Next x
If I change last lines of code to:
If nodeXML Is Nothing Then
Range("B" & x).Value = nodeXML2(i).Text
Else
Range("B" & x).Value = nodeXML(i).Text
End If
I only get value from tag "Billing client name" and no value if this tag doesn't exists
sample xml
<InvoiceData xmlns="http://tempuri.org/InvoiceData.xsd">
<INVOICE_HEADER>
<BILL_TO_CLIENTCODE/>
<CLIENTCODE>61138259</CLIENTCODE>
second one has got value in tag Bill to clientcode and in clientcode but Bill to clientcode should be primary.
xmlDoc.getElementsByTagName always return a collection, but that collection may be empty if there are no matches, so you need to test for (eg)
If nodeXML.Length > 0 Then
and not check whether nodeXML is Nothing
So something like this should work (untested):
Sub Tester()
Dim mainWorkBook As Workbook, xmlDoc As Object
Dim sht As Worksheet
Set mainWorkBook = ActiveWorkbook
Set sht = mainWorkBook.Sheets("Sheet3")
For x = 2 To sht.Cells(sht.Rows.Count, "A").End(xlUp).Row
Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.SetProperty "SelectionLanguage", "XPath"
xmlDoc.Async = False
xmlDoc.Load ("\\path\" & Range("A" & x) & ".xml")
sht.Range("B" & x).Value = PreferredValue(xmlDoc, _
Array("BILL_TO_CLIENTCODE", "CLIENTCODE"))
Next x
End Sub
Function PreferredValue(doc As Object, arrTags)
Dim t, col, rv
For Each t In arrTags
Set col = doc.getElementsByTagName(t)
If col.Length > 0 Then
rv = col(0).Text
If Len(rv) > 0 Then Exit For '<<<< EDIT
End If
Next t
PreferredValue = rv
End Function
Related
I have written a quite complex VBA script to run on a Word document to
transform it into an email body (together with a bunch of other documents),
combine it with other documents and save as pdf-attachment,
open email-distribution lists
create outlook items and put the distribution lists into a bcc field and body from earlier document
The script worked quite fine until it stopped for unclear to me reason. A "Run-time error '1001': Method 'Range' of object '_Global' failed." started to occur in the "Step 3 ...", specifically in the second line:
objLista.Worksheets(1).Activate
last_row = Range("A1").End(xlDown).Row
The script activates the worksheet just fine, but fails to do anything else with it. I tried to use explicit names of the workbook and worksheet in question, but it didn't help. The same lines in different yet similar script still work well. So I find it hard to find the source of the problem and correct it. I use MS Windows 10, and Office 365.
The whole script below:
Sub script()
' >>>>>>>>>>>>>>>>>>>>>>> Step 0. Declaration of variables and paths <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Dim Disclaimer_Path As String
Dim Email_Path As String
Dim objOutlook As Object
Dim objMail As Object
Dim ExcelApp As Excel.Application
Dim objLista As Workbook
Dim Today As String
Today = Format(Date, "yyyymmdd")
Disclaimer_Path = ...
Email_Path = "!_email.docx"
Distribution_list_Path = "!_List.xlsm"
Distribution_list_Path = "!_List_2.xlsm"
Pdf_Path = ...
Set objOutlook = CreateObject("Outlook.Application")
Set ExcelApp = New Excel.Application
' >>>>>>>>>>>>>>>>>>>>>>> Step 1. Creating e-mail body <<<<<<<<<<<<<<<<<<<<<<<<<<<
' First creating an email-body
Documents.Open FileName:=ActiveDocument.Path & "\1_News.docx"
Documents.Open FileName:=ActiveDocument.Path & "\2_Essay.docx"
Documents.Open FileName:=ActiveDocument.Path & "\3_Comment.docx"
Documents.Open FileName:=Disclaimer_Path
Documents.Open FileName:=Email_Path
Documents("1_News.docx").Activate
Selection.WholeStory
Selection.Copy
Documents("!_Email.docx").Activate
With Selection
.MoveDown
.MoveDown
.PasteAndFormat wdPasteDefault
End With
Documents("2_Essay.docx").Activate
Selection.WholeStory
Selection.Copy
Documents("!_Email.docx").Activate
Selection.PasteAndFormat wdPasteDefault
Documents("3_Comment.docx").Activate
Selection.WholeStory
Selection.Copy
Documents("!_Email.docx").Activate
With Selection
.PasteAndFormat wdPasteDefault
.WholeStory
End With
' Cleaning
Documents("2_Essay.docx").Close SaveChanges:=wdDoNotSaveChanges
Documents("3_Comment.docx").Close SaveChanges:=wdDoNotSaveChanges
Documents("Disclaimer.docx").Close SaveChanges:=wdDoNotSaveChanges
Stop
' >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Step 2. Creation of pdf <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Documents("1_News.docx").Activate
Selection.WholeStory
Selection.Copy
ThisDocument.Activate
With Selection
'.Range.Text = vbNewLine
.MoveDown
.PasteAndFormat wdPasteDefault
.Range.Text = vbNewLine
.MoveDown
End With
ActiveDocument.ActiveWindow.View.Type = wdMasterView
With ActiveDocument.Subdocuments
.AddFromFile Name:=ActiveDocument.Path & "\2_Essay.docx"
.AddFromFile Name:=ActiveDocument.Path & "\3_Comment.docx"
.AddFromFile Name:=ActiveDocument.Path & "\4_Preview.docx"
.AddFromFile Name:=ActiveDocument.Path & "\5_Comment_2.docx"
.AddFromFile Name:=ActiveDocument.Path & "\8_Calendar.docx"
.AddFromFile Name:=Disclaimer_Path
End With
'Returns to standard view
ActiveDocument.ActiveWindow.View.Type = wdPrintView
Selection.HomeKey Unit:=wdStory
Stop
ActiveDocument.ExportAsFixedFormat Pdf_Path, wdExportFormatPDF
' >>>>>>>>>>>>>>>>>>>>>>>> Step 3. Creating Distribution lists <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Set objLista = ExcelApp.Workbooks.Open(Distribution_list_Path)
ExcelApp.Visible = True
Dim lista_1 As String, lista_2 As String, lista_3 As String, lista_4 As String, lista_5 As String, lista_6 As String, lista_7 As String, lista_8 As String, lista_9 As String
lista_1 = ""
lista_2 = ""
lista_3 = ""
lista_4 = ""
lista_5 = ""
lista_6 = ""
lista_7 = ""
lista_8 = ""
lista_9 = ""
objLista.Worksheets(1).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_1 = lista_1 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(2).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_2 = lista_2 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(3).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_3 = lista_3 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(4).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_4 = lista_4 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(5).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_5 = lista_5 & "; " & Cells(i, 1).Value
Next i
objLista.Worksheets(6).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_6 = lista_6 & "; " & Cells(i, 1).Value
Next i
' Now differentr set of lists
Set objLista_2 = ExcelApp.Workbooks.Open(Distribution_list_Path_2)
objLista_2.Worksheets(1).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_7 = lista_7 & "; " & Cells(i, 1).Value
Next i
objLista_2.Worksheets(2).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_8 = lista_8 & "; " & Cells(i, 1).Value
Next i
objLista_2.Worksheets(3).Activate
last_row = Range("A1").End(xlDown).Row
For i = 1 To last_row
lista_9 = lista_9 & "; " & Cells(i, 1).Value
Next i
' >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Step 4. Creates e-mails <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Documents("!_Email.docx").Activate
Selection.Copy
For Each Item In Array(lista_1, lista_2, lista_3, lista_4, lista_5, lista_6, lista_7, lista_8, lista_9)
With objOutlook.CreateItem(0)
oAccount = ""
.bcc = Item
.Subject = "Weekly"
.Attachments.add Pdf_Path
Set Editor = .GetInspector.WordEditor
Editor.Content.Paste
.Display
End With
Next Item
'Cleaning
Documents("1_News.docx").Close SaveChanges:=wdDoNotSaveChanges
Documents("!_email.docx").Close SaveChanges:=wdDoNotSaveChanges
Workbooks("!_List.xlsm").Worksheets("List_1").Activate
Range("A1").Select 'To żeby uniknąć jednego z błędów, który się wcześniej wywalał, gdy arkusz był zamykany z kursorem w innym miejscu niż "A1"
Workbooks("!_List.xlsm").Close SaveChanges:=wdDoNotSaveChanges
Workbooks("!_List_2.xlsm").Worksheets(1).Activate
Range("A1").Select 'To żeby uniknąć jednego z błędów, który się wcześniej wywalał, gdy arkusz był zamykany z kursorem w innym miejscu niż "A1"
Workbooks("!_List_2.xlsm").Close SaveChanges:=wdDoNotSaveChanges
End Sub
I have certain ranges within an Excel file and I create an instance of Word template from within Excel VBA. This Word template has a bunch of Doc variables so that I can replace the values of those Doc Variables with my defined variables using precise Excel sheet ranges. For some weird reason, Doc variable laid down in Word template file are not being updated.
Could someone please extend your help and advise what possible mistake I might be making here.
Sub Generate_CoverLetter()
Dim client, bo, invoice_currency, vesselName As String
Dim invoiceAmount 'As Single
Dim bo_rng, rngBO, rngCustName, rngAmount, rngVesselName, rngCurrencyCode, rngCommencedDate As Range
Dim SearchParams As Variant
Dim SearchParamsCols As Variant
Dim wdApp As Object
Dim wdDoc As Word.Document
Set bo_rng = Application.InputBox( _
Title:="Select BO range", _
Prompt:="Select a cell to pull in BO number....", _
Type:=8)
bo = bo_rng.value
lastRow = Range("A" & Application.Rows.Count).End(xlUp).Row
SearchParams = Array("field_19", "customer_name", "total_amount", "invoice_currency_code", "field_43", "field_71")
orderColumn = seachParamColumn(SearchParams(0))
cnameColumn = seachParamColumn(SearchParams(1))
amountColumn = seachParamColumn(SearchParams(2))
currencyColumn = seachParamColumn(SearchParams(3))
commencedDateColumn = seachParamColumn(SearchParams(4))
vesselColumn = seachParamColumn(SearchParams(5))
' core ranges
Set rngBO = Range(Cells(2, orderColumn), Cells(lastRow, orderColumn))
Set rngCustName = Range(Cells(2, cnameColumn), Cells(lastRow, cnameColumn))
Set rngAmount = Range(Cells(2, amountColumn), Cells(lastRow, amountColumn))
Set rngVesselName = Range(Cells(2, vesselColumn), Cells(lastRow, vesselColumn))
' invoice parameter ranges
Set rngCurrencyCode = Cells(bo_rng.Row, currencyColumn)
Set rngCommencedDate = Cells(bo_rng.Row, commencedDateColumn)
client = Cells(bo_rng.Row, rngCustName.Column)
InvoiceNumber = Cells(bo_rng.Row, 1) ' .value
invoice_currency = rngCurrencyCode.value
invoiceAmount = Application.WorksheetFunction.SumIfs(rngAmount, rngBO, "=" & bo, rngCustName, "=" & client)
invoiceAmount = Format(invoiceAmount, "#,##0.00")
commencedDate = rngCommencedDate.value
' This weird looking loop is here because an order might have several rows in Excel data
' but only one of those rows might have the name of the vessel
For Each cell In rngVesselName.SpecialCells(xlCellTypeVisible)
If cell.Column = vesselColumn And Not IsEmpty(cell) Then
vesselName = cell.value
Exit For
End If
Next
MsgBox InvoiceNumber & vbLf & _
invoice_currency & " " & invoiceAmount & vbLf & _
client & vbLf & _
vesselName & vbLf & _
commencedDate
Set wdApp = CreateObject("Word.Application")
wdApp.Visible = True
Set wdDoc = wdApp.Documents.Add
Set wdDoc = wdApp.Documents.Open("C:\Users\smiq\Documents\Custom Office Templates\CL.dotm")
Set wdDoc = ActiveDocument
wdDoc.Activate
wdApp.WindowState = wdWindowStateMaximize
ActiveDocument.Variables("wd_vesselName").value = vesselName
ActiveDocument.Variables("wd_CommencedDate").value = commencedDate
ActiveDocument.Variables("wd_invoiceNumber").value = InvoiceNumber
ActiveDocument.Variables("wd_invoiceAmount").value = invoiceAmount
End Sub
Function seachParamColumn(param As Variant)
Dim c
With Range("1:1")
Set c = .Find(param, , xlValues)
If Not c Is Nothing Then
seachParamColumn = Range(c.Address).Column
End If
End With
End Function
I have the following code that fills in a word document template.
What I want to do is to create a new document for each row as I fill in the worksheet.
I tried changing the bookmark's Range by adding
Range("e5").Select
Do Until ActiveCell.Value = ""
loop
But the whole thing crashed...
Sub CreateWR()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim objword As Object
Set objword = CreateObject("Word.Application")
objword.Visible = True
objword.Documents.Open ("C:\User\Documents\FileControl\template.doc")
With objword.ActiveDocument
.Bookmarks("PropertyName").Range.Text = ws.Range("a2").Value
.Bookmarks("ProjectNumber").Range.Text = ws.Range("b2").Value
.Bookmarks("BudgetNumber").Range.Text = ws.Range("c2").Value
.Bookmarks("ProjecName").Range.Text = ws.Range("d2").Value
.Bookmarks("Vendor_1").Range.Text = ws.Range("e2").Value
.Bookmarks("Price_1").Range.Text = ws.Range("f2").Value
.Bookmarks("Vendor_2").Range.Text = ws.Range("g2").Value
.Bookmarks("Price_2").Range.Text = ws.Range("h2").Value
.Bookmarks("Vendor_3").Range.Text = ws.Range("i2").Value
.Bookmarks("Price_3").Range.Text = ws.Range("j2").Value
.Bookmarks("Vendor_1_2").Range.Text = ws.Range("e2").Value
.Bookmarks("RequestedBy").Range.Text = ws.Range("m2").Value
End With
End Sub
This is not your final solution, as it's not 100% clear what the upper value should be for the row counter, but to give you a start, see below.
The For loops the number of rows. For the moment, I've put 5 there, for you to test whether the basics work.
The document is generated inside this loop. Note that Open has been changed to Add in order to create a new document from the template. Also, the object variable objDoc is declared at the top and the new document assigned to it. This is also used to address the bookmarks, rather than ActiveDocument. At the end of the loop objDoc is set to Nothing in preparation for the next iteration.
The rowCounter has been substituted for the static row values in the original code, so each loop will move to the next row.
Sub CreateWR()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
Dim rowCounter as Long
Dim objword As Object
Dim objDoc as Object
Set objword = CreateObject("Word.Application")
objword.Visible = True
For rowCounter = 2 to 5
Set objDoc = objword.Documents.Add ("C:\User\Documents\FileControl\template.doc")
With objDoc
.Bookmarks("PropertyName").Range.Text = ws.Range("a" & CStr(rowCounter)).Value
.Bookmarks("ProjectNumber").Range.Text = ws.Range("b" & CStr(rowCounter)).Value
.Bookmarks("BudgetNumber").Range.Text = ws.Range("c" & CStr(rowCounter)).Value
.Bookmarks("ProjecName").Range.Text = ws.Range("d" & CStr(rowCounter)).Value
.Bookmarks("Vendor_1").Range.Text = ws.Range("e" & CStr(rowCounter)).Value
.Bookmarks("Price_1").Range.Text = ws.Range("f" & CStr(rowCounter)).Value
.Bookmarks("Vendor_2").Range.Text = ws.Range("g" & CStr(rowCounter)).Value
.Bookmarks("Price_2").Range.Text = ws.Range("h" & CStr(rowCounter)).Value
.Bookmarks("Vendor_3").Range.Text = ws.Range("i" & CStr(rowCounter)).Value
.Bookmarks("Price_3").Range.Text = ws.Range("j" & CStr(rowCounter)).Value
.Bookmarks("Vendor_1_2").Range.Text = ws.Range("e" & CStr(rowCounter)).Value
.Bookmarks("RequestedBy").Range.Text = ws.Range("m" & CStr(rowCounter)).Value
End With
Set objDoc = Nothing
Next
End Sub
I've got a vbscript that converts a specific range of rows to a csv file.
My problem is it also copies empty rows and not needed blue rows. How can I delete this complete empty rows before copying or exclude them from copying?
My code:
Public Sub xlsToCsv()
Const WorkingDir = "C:\Test\"
Const xlCSV = 24
Const xlUp = -4162
Dim fso, SaveName, myFile
Dim objExcel, objWorkbook, wsSource, wsTarget
myFile = "source_file.xlsx"
SaveName = "test.csv"
With CreateObject("Scripting.FilesystemObject")
If Not .FileExists(WorkingDir & myFile) Then
MsgBox "File not found:" & vbCrLf & WorkingDir & myFile, vbInformation, "Script Cancelled"
WScript.Quit
End If
End With
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
objExcel.DisplayAlerts = False
Set objWorkbook = objExcel.Workbooks.Open(WorkingDir & myFile)
Set wsSource = objWorkbook.Sheets(1)
Set wsTarget = objWorkbook.Sheets.Add()
With wsTarget
.Cells(1,1).Value = "ID"
.Cells(1,2).Value = "NAME"
.Cells(1,3).Value = "DESC"
End With
With wsSource
.Range("F7", .Range("F" & .Rows.Count).End(xlUp)).Copy wsTarget.Range("A2")
.Range("A7", .Range("A" & .Rows.Count).End(xlUp)).Copy wsTarget.Range("B2")
.Range("E7", .Range("E" & .Rows.Count).End(xlUp)).Copy wsTarget.Range("C2")
End With
objWorkbook.SaveAs WorkingDir & SaveName, xlCSV
objWorkbook.Close True
Set objWorkbook = Nothing
Set objExcel = Nothing
Set fso = Nothing
Set myFolder = Nothing
End Sub
call xlsToCsv()
Option explicit
'// Define the blue color here
dim ibluecolor: ibluecolor = 15652797 ' this is 40% Accent1
Public Sub xlsToCsv()
Const WorkingDir = "C:\Test\"
Const xlCSV = 24
Const xlUp = -4162
Dim fso, SaveName, myFile, myFolder
Dim objExcel, objWorkbook, wsSource, wsTarget
myFile = "source_file.xlsx"
SaveName = "test.csv"
With CreateObject("Scripting.FilesystemObject")
If Not .FileExists(WorkingDir & myFile) Then
MsgBox "File not found:" & vbCrLf & WorkingDir & myFile, vbInformation, "Script Cancelled"
WScript.Quit
End If
End With
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
objExcel.DisplayAlerts = False
Set objWorkbook = objExcel.Workbooks.Open(WorkingDir & myFile)
Set wsSource = objWorkbook.Sheets(1)
Set wsTarget = objWorkbook.Sheets.Add()
With wsTarget
.Cells(1,1).Value = "ID"
.Cells(1,2).Value = "NAME"
.Cells(1,3).Value = "DESC"
End With
dim Fcol, Acol, Ecol
With wsSource
set Fcol = .Range("F7", .Range("F" & .Rows.Count).End(xlUp))
set Acol = .Range("A7", .Range("A" & .Rows.Count).End(xlUp))
set Ecol = .Range("E7", .Range("E" & .Rows.Count).End(xlUp))
End With
With wsTarget
Fcol.Copy .Range("A2")
Acol.Copy .Range("B2")
Ecol.Copy .Range("C2")
End With
dim Frc, Arc, Erc
Frc = Fcol.Rows.Count
Arc = Acol.Rows.Count
Erc = Ecol.Rows.Count
dim rowcount
rowcount = Max(Arc, Frc, Erc)
dim ix
with wsTarget
for ix = rowcount + 1 to 2 step -1
if Len(.cells(ix,1))=0 and len(.cells(ix,2))=0 and len(.cells(ix,3))=0 then
.rows(ix).delete
'//Check for blue rows assuming all cells in the row have the same color
elseif .cells(ix, 1).Interior.Color = iBlueColor then
.rows(ix).delete
end if
next
End With
objWorkbook.SaveAs WorkingDir & SaveName, xlCSV
objWorkbook.Close True
Set objWorkbook = Nothing
Set objExcel = Nothing
Set fso = Nothing
Set myFolder = Nothing
End Sub
call xlsToCsv()
Function Max(v1, v2, v3)
select case true
case v1 => v2 and v1 => v3
Max = v1
case v2 => v3
Max = v2
case else
Max = v3
end select
end function
This is an alternative approach to my original in an attempt to improve performance. In this case, instead of using Excel to create the csv file, the VBScript code writes the csv file directly using a text file created by FileSystemObject. I have tested this with a larger set of source data and it seems to be quite a bit quicker than the original - about 40 seconds for 1500 rows. There is still an overhead of opening the Excel application (about 5-10 seconds) but there's not much you can do about that. If performance is important to you there may be other improvements that you could do.
If you have numeric values in the spreadsheet, you may need to do some formatting to convert to string values suitable for csv output, because Excel tends to use exponential notation for numbers converted to text, which is not always what you want. I have also used quotation marks and comma separators but you could use different formatting conventions for your CSV output. You may want to change the use of WriteLine because this appends a CrLf after the last line, which might be interpreted downstream as a blank row.
Option explicit
'// Define the blue color here
dim ibluecolor: ibluecolor = 15652797 ' this is 40% Accent1
msgbox "starting"
call xlsToCsv()
msgbox "finished"
Public Sub xlsToCsv()
Const WorkingDir = "C:\Test\"
Const xlCSV = 24
Const xlUp = -4162
Dim fso, SaveName, myFile, myFolder
Dim objExcel, objWorkbook, wsSource, wsTarget
Dim oOutputFile
myFile = "source_file.xlsx"
SaveName = "test2.csv"
With CreateObject("Scripting.FilesystemObject")
'// Check that the input file exists
If Not .FileExists(WorkingDir & myFile) Then
MsgBox "File not found:" & vbCrLf & WorkingDir & myFile, vbInformation, "Script Cancelled"
WScript.Quit
End If
'// Create a text file to be the output csv file
'// Overwrite v v False=ASCII format use True for Unicode format
set oOutputFile = .CreateTextFile( WorkingDir & SaveName, True, False)
End With
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False
objExcel.DisplayAlerts = False
Set objWorkbook = objExcel.Workbooks.Open(WorkingDir & myFile)
Set wsSource = objWorkbook.Sheets(1)
oOutputFile.WriteLine """ID"",""NAME"",""DESC"""
'// Get the three column ranges, starting at cells in row 7
dim Fcol, Acol, Ecol
With wsSource
set Fcol = .Range("F7", .Range("F" & .Rows.Count).End(xlUp))
set Acol = .Range("A7", .Range("A" & .Rows.Count).End(xlUp))
set Ecol = .Range("E7", .Range("E" & .Rows.Count).End(xlUp))
End With
'// Get the number of rows in each column
dim Frc, Arc, Erc
Frc = Fcol.Rows.Count
Arc = Acol.Rows.Count
Erc = Ecol.Rows.Count
'// Rowcount is the max row of the three
dim rowcount
rowcount = Max(Arc, Frc, Erc)
dim AVal, FVal, EVal
dim ix
for ix = 1 to rowcount
'// Note - row 1 of each column is actually row 7 in the workbook
AVal = REPLACE(ACol.Cells(ix, 1), """", """""")
EVal = REPLACE(ECol.Cells(ix, 1), """", """""")
FVal = REPLACE(FCol.Cells(ix, 1), """", """""")
'// Check for an empty row
if Len(AVal)=0 and len(EVal)=0 and len(FVal)=0 then
'// skip this row
'// Check for a blue row
elseif ACol.cells(ix,1).Interior.Color = iBlueColor then
'// skip this row
else
'// Write the line to the csv file
oOutputFile.WriteLine """" & FVal & """,""" & AVal & """,""" & EVal & """"
end if
next
'// Close the output file
oOutputFile.Close
'// Close the workbook
objWorkbook.Close True
objExcel.Quit
'// Clean up
Set oOutputFile = Nothing
Set objWorkbook = Nothing
Set objExcel = Nothing
Set fso = Nothing
Set myFolder = Nothing
End Sub
Function Max(v1, v2, v3)
select case true
case v1 >= v2 and v1 >= v3
Max = v1
case v2 >= v3
Max = v2
case else
Max = v3
end select
end function
I have an Excel sheet that has a list of contact names, company names and email addresses.
I want to export these to Outlook.
I have done some code to delete current entries in a contact folder using VBA from Excel, but when adding a new contact, I am getting a 438 Runtime error.
Code to add a contact:
Sub addnewcontacts()
Dim runoutlook As Outlook.Application
Set runoutlook = CreateObject("Outlook.Application")
Set findnamespace = runoutlook.GetNamespace("MAPI")
Set activefolder = findnamespace.Folders
n = 1
Do Until activefolder.Item(n) = "user#domain.co.uk"
n = n + 1
Loop
Set myfolder = activefolder.Item(n)
Set myfolder2 = myfolder.Folders("Contacts").Folders("CustGBP")
lastrow = Sheets("Data").Range("A" & Sheets("Data").Rows.Count).End(xlUp).Row
For i = 1 To lastrow
Sheets("Sage Data").Activate
If ActiveSheet.Range("C" & i).Value = "" Then
' IT BREAKS AT THIS LINE
Set olitem = myfolder2.CreateItem(olContactItem)
With olitem
.FullName = Trim(Range("A" & i).Value).
.Company = Trim(Range("B" & i).Value)
.Email1Address = Range("G" & i).Value
End With
olitem.Save
End If
Next i
End Sub
Working delete code:
Sub outlookdelete()
Dim runoutlook As Outlook.Application
Set runoutlook = CreateObject("Outlook.Application")
Set findnamespace = runoutlook.GetNamespace("MAPI")
Set activefolder = findnamespace.Folders
n = 1
Do Until activefolder.Item(n) = "user#domain.co.uk"
n = n + 1
Loop
Set myfolder = activefolder.Item(n)
Set myfolder2 = myfolder.Folders("Contacts").Folders("CustGBP")
Do
For Each ContactItem In myfolder2.Items
ContactItem.Delete
Next ContactItem
' this is in as otherwise it would only delete a handful
' each time it ran for some reason
Loop Until myfolder2.Items.Count = 0
End Sub
You have to create the item from the application itself (i.e. your runoutlook Outlook Object) and then move it to the desired folder. Starting at where you encounter the error, you can update your code with the following
// Creates a contact Item in the default Contacts folder
Set olitem = runoutlook.CreateItem(olContactItem)
With olitem
.FullName = Trim(Range("A" & i).Value)
.Company = Trim(Range("B" & i).Value) ' may need to change to "CompanyName"
.Email1Address = Range("G" & i).Value
.Move DestFldr:=myfolder2 // moves the contact to the indicated folder
.Save
End With
As for the deletion of all the contacts, you can try this code instead
Do While myfolder2.Items.Count <> 0
myfolder2.Items.Remove (1)
Loop
This is how I managed to get it working myself
For i = 1 To lastrow
Sheets("Data").Activate
If ActiveSheet.Range("C" & i).Value = "" Then
Set olitem = myfolder2.Items.Add(olContactItem)
With olitem
.FullName = Trim(Range("A" & i).Value)
.CompanyName = Trim(Range("B" & i).Value)
.Email1Address = Range("G" & i).Value
.Save
End With
End If
Application.StatusBar = "Updating Contacts: " & Format(i / lastrow, "Percent") & " Complete"
Next i