Connect Excel to Google Sheets using VBA - excel

I'm using Excel to create a form that is linked to another sheet that acts as a database.
This is my form (worksheet's name : "Form"):
And this is part of the database (worksheet's name: "Data"):
Right now it connects using a VBA script that is activated using the "save" button (green). Here's parts of the script:
Private Sub destBook()
setFormBook
If (destinationBook Is Nothing) Then
Dim file As String
file = ThisWorkbook.Sheets("_options").Cells(2, 26).Value //"path/to/the/database/file.xlsx"
If (IsEmpty(file)) Then
ThisWorkbook.Sheets("_options").Select
ThisWorkbook.Sheets("_options").Cells(2, 26).Select
Dim m As VbMsgBoxResult
m = MsgBox("")
Else
Set destinationBook = Workbooks.Open(file)
End If
End If
End Sub
Sub SaveClick()
Dim dataIdx As Integer
dataIdx = GetIdx()
If (dataIdx >= 2) Then
destBook
If (hasLock() = False) Then
WarnNoLock
closeDst
Else
Dim mappingRng As Range: Set mappingRng = ThisWorkbook.Sheets("_mappings").Range("F2:F71")
Dim rowIdx As Integer
For rowIdx = 1 To mappingRng.Rows.count
Dim FormRange As Range
Set FormRange = mappingRng.Cells(RowIndex:=rowIdx, ColumnIndex:=1)
If FormRange <> "" Then
Dim dataCol As Integer
Dim newValue As String
dataCol = mappingRng.Cells(RowIndex:=rowIdx, ColumnIndex:=2)
newValue = ThisWorkbook.Sheets("Form").Range(FormRange).Value
destinationBook.Sheets("Data").Cells(dataIdx, dataCol).Value = newValue
End If
Next
' refresh
Application.CalculateFull
End If
' close & save
closeDst
End If
End Sub
My question : Instead of saving/re-writing the data (Form) to another Excel file (Data), is it possible to save/re-write the data (Form) to a Google Sheet document ?
My guess would be to use the sharing link, but not sure how to make it works.

you can import JsonConverter.bas into your project (Open VBA Editor, Alt + F11; File > Import File) from https://github.com/VBA-tools/VBA-JSON/releases
and make table in your excel sheet, input this code to your module
Sub ConnectSheets()
Set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP.6.0") 'To use POST http Request
'Get data table as JSON
tableData = JsonConverter.ConvertToJson(Sheets("Page1").ListObjects("Table1").Range.Value)
' 'Create All Json to Send
Data = "{""dataReq"": " & vbNewLine & tableData & vbNewLine & ", " & vbNewLine & " ""fname"":""pasteData""}"
Debug.Print Data
'Define the google URL
myurl = "https://script.google.com/macros/s/AKfycbzE0nm-Jz2yE4IWc7OB_ter8NrNKBL9SXuxi6cG74FeUpwCx6T9tFZyPd13dRxgaqEm/exec"
xmlhttp.Open "POST", myurl, False 'define method to use
xmlhttp.Send Data 'execute call
sGetResult = xmlhttp.ResponseText 'read response
Debug.Print sGetResult 'view response
End Sub
and put code to your google sheet, apply as webapp
function doPost(request = {}) {
const { parameter, postData: { contents, type } = {} } = request; //request data
const { dataReq = {} } = JSON.parse(contents); //content
const { fname = {} } = JSON.parse(contents); //function name
const response = {
status: "function not found: " + fname, // prepare response in function not found
data2: dataReq
}
switch (fname) { //function selection
case 'pasteData':
var output = JSON.stringify(pasteData(dataReq)) //call function with data, name and type from request
break
default:
var output = JSON.stringify(response)
break
}
return ContentService.createTextOutput(output).setMimeType(ContentService.MimeType.JSON); //response to frontend
}
function pasteData(dataReq) {
const id = '1wtGM5QL0LwIYJoU9joOO31n_kBbJJJHRFaKtIdwWOeU'; //id of Google Sheet
var sheet = SpreadsheetApp.openById(id).getSheetByName('Page1'); //sheet
sheet.clear(); //delete data
sheet.getRange(1, 1, dataReq.length, dataReq[0].length).setValues(dataReq); // paste new data
return "Numbers of sheets added: "+ dataReq.length; //return a response
}

Related

Parsing all prices of same field name if found in sheet from json data vba in a listbox and let user choose

So I have some json formatted data, in which an article name (the field in my case is "description courte") can be used multiple times and have a different price each time, I want to get those prices and display them in a listbox and let the user pick which one to parse in the column "price" which is found.offset(0,3). Note that I only search for fields that exist in the Range("G:G") This is what I did so far :
This code is returning an error : index does not belong in the selection (sorry if translated badly) at the
Set Found = Range("G:G").Find(ArtDict.Items()(Index).Name)
Code example
Sub prix()
Dim http As New WinHttpRequest
Dim resp As String
Dim url As String
url = "https://api.airtable.com/v0/appY6Wo3AmLHqHkjr/Materiaux?api_key=key_here" & Fields
http.Open "GET", url, False
http.Send
Dim JSON As Object
Dim Found As Range
Dim ArtDict As New Dictionary, Article As class_Article
Dim Index As Long, count As Long
Set JSON = JsonConverter.ParseJson(http.ResponseText)
For Index = 1 To JSON("records").count
Set Found = Range("G:G").Find(ArtDict.Items()(Index).Name)
If Not ArtDict.Exists(JSON("records")(Index)("fields")("description courte")) Then
'If this article doesn't exist in the article dictionary, then create the article object and add it to the dictionary
Set Article = New class_Article
Article.Name = JSON("records")(Index)("fields")("description courte")
Article.ParsePrice JSON("records")(Index)("fields")("prix unitaire HT")
Debug.Print Article.Name, Article.HighPrice, Article.LowPrice
ArtDict.Add Article.Name, Article
Else
Set Article = ArtDict(JSON("records")(Index)("fields")("description courte"))
Article.ParsePrice JSON("records")(Index)("fields")("prix unitaire HT")
Debug.Print Article.Name, Article.HighPrice, Article.LowPrice
Set ArtDict(JSON("records")(Index)("fields")("description courte")) = Article
End If
If Not Found Is Nothing Then
count = Found.Offset(0, 4).Value + 1
If count > 1 Then
UserForm1.Show
UserForm1.ListBox1.AddItem (Article.HighPrice)
UserForm1.ListBox1.AddItem (Article.LowPrice)
Found.Offset(0, 3) = UserForm1.ListBox1.Value
End If
End If
Next Index
End Sub
JSON SAMPLE
{
"records": [
{
"id": "rec0MS66BnYY0vK32",
"fields": {
"id": 124,
"article": "osmo 24m2 3062MAT 0.75L",
"categorie": [
"recvw95DBiWvk3zaH"
],
"udv": 1,
"unité": [
"recYQ9wpLDgNDk5BW"
],
"prix HT de l'udv": 29.09,
"date d'achat": "2019-08-01",
"distributeur": "cotet mtp",
"reference distributeur": "OSMO-ORI-0.75-M",
"id facture": "FA19036300",
"created on": "2020-02-07",
"by": "remyvignaux",
"description courte": "osmo 3062MAT",
"prix unitaire HT": 29.09
},
"createdTime": "2021-02-28T20:53:00.000Z"
},....etc
CLASS_ARTICLE
Option Explicit
Public Name As String
Public HighPrice As Currency
Public LowPrice As Currency
Private Sub Class_Initialize()
HighPrice = -922337203685477.5807# 'Set value to lowest possible value
LowPrice = 922337203685477.5807# 'Set value to the highest possible value
End Sub
Public Function ParsePrice(ByVal NewPrice As Currency) As Boolean
HighPrice = IIf(NewPrice > HighPrice, NewPrice, HighPrice)
LowPrice = IIf(NewPrice < LowPrice, NewPrice, LowPrice)
End Function
Parse the JSON into a collection of articles (using a dictionary) and then process each article in turn. The price selection can be an article method. I used an input box just to show the principle but you could use listbox. The results are shown on Sheet1.
Option Explicit
Sub prix()
' get json into a string
Dim fso, ts, s
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile("c:\temp\json.txt")
s = ts.ReadAll
ts.Close
Dim dictArt As New Dictionary, oArt As Class_Article ' holds articles
Dim name As String, price As Currency
Dim JSON As Object, rec, fld
Set JSON = JsonConverter.ParseJson(s)
' parse json
For Each rec In JSON("records")
Set fld = rec("fields")
name = fld("description courte")
price = fld("prix unitaire HT")
If dictArt.Exists(name) Then
dictArt(name).AddPrice price
Else
Set oArt = New Class_Article
oArt.name = name
oArt.AddPrice price
dictArt.Add name, oArt
End If
Next
' result to sheet1
Dim key, i As Long: i = 1
Sheet1.Cells.Clear
Sheet1.Range("A1:C1") = Array("Description", "Price Count", "Price")
For Each key In dictArt
i = i + 1
Set oArt = dictArt(key)
Sheet1.Cells(i, 1) = oArt.Name
Sheet1.Cells(i, 2) = oArt.PriceCount
' if more than once give options
If oArt.PriceCount > 1 Then
Sheet1.Cells(i, 1).Select
Sheet1.Cells(i, 3).Interior.Color = vbYellow
oArt.SelectPrice
If oArt.bSelected Then
Sheet1.Cells(i, 3) = oArt.price
Sheet1.Cells(i, 3).Interior.Color = xlNone
End If
Else
Sheet1.Cells(i, 3) = oArt.price
End If
Next
End Sub
' Class_Article
Public name As String
Public price As Currency
Public PriceCount As Integer
Public bSelected As Boolean
Private prices As New Collection
Private i As Integer
Public Sub AddPrice(ByVal price As Currency)
PriceCount = PriceCount + 1
Me.price = price
prices.Add price, CStr(PriceCount)
End Sub
Sub SelectPrice()
Dim msg As String
bSelected = False
' build option list
msg = name & " has " & PriceCount & " prices"
For i = 1 To PriceCount
msg = msg & vbCr & "(" & i & ") " & prices(i)
Next
' user selects
begin:
i = Application.InputBox(msg, "Select Price 1 to " & PriceCount, 1, Type:=1) ' int
If i < 1 Then
Exit Sub
ElseIf i > PriceCount Then
GoTo begin
End If
' selected price
price = prices(i)
bSelected = True
End Sub

Accessing SurveyMonkey API from VBA

I am tying to set-up a Excel VBA project to readout individual survey responses into a form in Excel for some calculations and then PDF reporting.
However I have great difficulty to deploy the .NET library (SurveyMonkeyApi) to be available for reference in VBA.
I have set up a VisualStudio project to test that way , and I can install it for that specific VS project (through NuGet PM). But the library is not made available for Excel on that machine.
I have downloaded (on another machine) the libraries through standalone NuGet and they download OK but then I am at loss on how to register for Excel VBA access. On top of it there is a dependency on NewtonsoftJson library too (which downloaded automatically on both occasions).
Good advice appreciated!
I just saw this now - is there a feature for StackOverflow to alert me when a comment is added or a question answered, so I know to look back?
Here is starting code:
Option Explicit
Public Const gACCESS_TOKEN As String = "xxxxxxxxxxxxxxxxxxxxxx"
Declare Function GetTickCount Lib "kernel32" () As Long
Declare Sub Sleep Lib "kernel32" (ByVal lngMilliSeconds As Long)
' for a JSON parser see https://code.google.com/p/vba-json/
Public Sub test()
Dim vRequestBody As Variant, sResponse As String, sSurveyID As String
sSurveyID = "1234567890"
vRequestBody = "{""survey_id"":" & """" & sSurveyID & """" _
& ", ""fields"":[""collector_id"", ""url"", ""open"", ""type"", ""name"", ""date_created"", ""date_modified""]" _
& "}"
sResponse = SMAPIRequest("get_collector_list", vRequestBody)
End Sub
Function SMAPIRequest(sRequest As String, vRequestBody As Variant) As String
Const SM_API_URI As String = "https://api.surveymonkey.net/v2/surveys/"
Const SM_API_KEY As String = "yyyyyyyyyyyyyyyyyyyyyyyy"
Dim bDone As Boolean, sMsg As String, sUrl As String, oHttp As Object ' object MSXML2.XMLHTTP
Static lsTickCount As Long
If Len(gACCESS_TOKEN) = 0 Then
Err.Raise 9999, "No Access token"
End If
On Error GoTo OnError
sUrl = SM_API_URI & URLEncode(sRequest) & "?api_key=" & SM_API_KEY
'Debug.Print Now() & " " & sUrl
Application.StatusBar = Now() & " " & sRequest & " " & Left$(vRequestBody, 127)
Set oHttp = CreateObject("MSXML2.XMLHTTP") ' or "MSXML2.ServerXMLHTTP"
Do While Not bDone ' 4.33 offer retry
If GetTickCount() - lsTickCount < 1000 Then ' if less than 1 sec since last call, throttle to avoid sResponse = "<h1>Developer Over Qps</h1>"
Sleep 1000 ' wait 1 second so we don't exceed limit of 2 qps (queries per second)
End If
lsTickCount = GetTickCount()
'Status Retrieves the HTTP status code of the request.
'statusText Retrieves the friendly HTTP status of the request.
'Note The timeout property has a default value of 0.
'If the time-out period expires, the responseText property will be null.
'You should set a time-out value that is slightly longer than the expected response time of the request.
'The timeout property may be set only in the time interval between a call to the open method and the first call to the send method.
RetryPost: ' need to do all these to retry, can't just retry .Send apparently
oHttp.Open "POST", sUrl, False ' False=not async
oHttp.setRequestHeader "Authorization", "bearer " & gACCESS_TOKEN
oHttp.setRequestHeader "Content-Type", "application/json"
oHttp.send CVar(vRequestBody) ' request body needs brackets EVEN around Variant type
'-2146697211 The system cannot locate the resource specified. => no Internet connection
'-2147024809 The parameter is incorrect.
'String would return {"status": 3, "errmsg": "No oJson object could be decoded: line 1 column 0 (char 0)"} ??
'A Workaround would be to use parentheses oHttp.send (str)
'"GET" err -2147024891 Access is denied.
'"POST" Unspecified error = needs URLEncode body? it works with it but
SMAPIRequest = oHttp.ResponseText
'Debug.Print Now() & " " & Len(SMAPIRequest) & " bytes returned"
sMsg = Len(SMAPIRequest) & " bytes returned in " & (GetTickCount() - lsTickCount) / 1000 & " seconds: " & sRequest & " " & Left$(vRequestBody, 127)
If Len(SMAPIRequest) = 0 Then
bDone = MsgBox("No data returned - do you wish to retry?" _
& vbLf & sMsg, vbYesNo, "Retry?") = vbNo
Else
bDone = True ' got reply.
End If
Loop ' Until bdone
Set oHttp = Nothing
GoTo ExitProc
OnError: ' Pass True to ask the user what to do, False to raise to caller
Select Case MsgBox(Err.Description, vbYesNoCancel, "SMAPIRequest")
Case vbYes
Resume RetryPost
Case vbRetry
Resume RetryPost
Case vbNo, vbIgnore
Resume Next
Case vbAbort
End
Case Else
Resume ExitProc ' vbCancel
End Select
ExitProc:
End Function
Public Function URLEncode(StringVal As String, Optional SpaceAsPlus As Boolean = False) As String
Dim StringLen As Long
StringLen = Len(StringVal)
If StringLen > 0 Then
ReDim result(StringLen) As String
Dim i As Long, CharCode As Integer
Dim Char As String, Space As String
If SpaceAsPlus Then Space = "+" Else Space = "%20"
For i = 1 To StringLen
Char = Mid$(StringVal, i, 1)
CharCode = Asc(Char)
Select Case CharCode
Case 97 To 122, 65 To 90, 48 To 57, 45, 46, 95, 126
result(i) = Char
Case 32
result(i) = Space
Case 0 To 15
result(i) = "%0" & Hex(CharCode)
Case Else
result(i) = "%" & Hex(CharCode)
End Select
Next i
URLEncode = Join(result, "")
End If
End Function
EDIT 23-APRIL add more code.
the Me. comes from code in a Userform.
Set jLib = New JSONLib
vRequestBody = "{"
If Me.txtDaysCreated > "" Then
vRequestBody = vRequestBody & JKeyValue("start_date", Format$(Now() - CDbl(Me.txtDaysCreated), "yyyy-mm-dd")) & ","
End If
If Me.txtTitleContains > "" Then
' title contains "text", case insensitive
vRequestBody = vRequestBody & JKeyValue("title", Me.txtTitleContains) & ","
End If
vRequestBody = vRequestBody _
& JKeyValue("fields", Array("title", "date_created", "date_modified", "num_responses", _
"language_id", "question_count", "preview_url", "analysis_url")) & "}"
'returns in this order: 0=date_modified 1=title 2=num_responses 3=date_created 4=survey_id
' and in date_created descending
sResponse = GetSMAPIResponse("get_survey_list", vRequestBody)
------------------------------------------
Function JKeyValue(sKey As String, vValues As Variant) As String
Dim jLib As New JSONLib
JKeyValue = jLib.toString(sKey) & ":" & jLib.toString(vValues)
Set jLib = Nothing
End Function
Edit 25-April overview of VBA code to get the data
This is covered in the SM documentation, but I'll sketch how that looks in VBA.
the response to get_survey_details gives you all the survey setup data. Use
Set oJson = jLib.parse(Replace(sResponse, "\r\n", " "))
to get a json object.
Set dictSurvey = oJson("data")
gives you the dictionary so you can get data like dictSurvey("num_responses"). I take it you know how to index into dictionary objects to get field values.
Set collPages = dictSurvey("pages")
gives you a collection of Pages. The undocumented field "position" gives you the order of pages in the survey UI.
For lPage = 1 To collPages.Count
Set dictPage = collPages(lPage)
Set collPageQuestions = dictPage("questions") ' gets you the Qs on this page
For lPageQuestion = 1 To collPageQuestions.Count
Set dictQuestion = collPageQuestions(lPageQuestion) ' gets you one Q
Set collAnswers = dictQuestion("answers") ' gets the QuestionOptions for this Q
For lAnswer = 1 To collAnswers.Count
Set dictAnswer = collAnswers(lAnswer) ' gets you one Question Option
etc etc
Then given the number of responses from above, loop through the respondents 100 at a time - again see the SM doc for details of how to specify start and end dates to do incremental downloads over time.
create a json object from the response to "get_respondent_list"
Collect the fields for each respondent and accumulate a list of at most 100 respondent IDs.
Then "get_responses" for that list.
Set collResponsesData = oJson("data")
For lResponse = 1 To collResponsesData.Count
If not IsNull(collResponsesData(lResponse)) then
... get fields...
Set collQuestionsAnswered = collResponsesData(lResponse)("questions")
For lQuestion = 1 To collQuestionsAnswered.Count
Set dictQuestion = collQuestionsAnswered(lQuestion)
nQuestion_ID = CDbl(dictQuestion("question_id"))
Set collAnswers = dictQuestion("answers") ' this is a collection of dictionaries
For lAnswer = 1 To collAnswers.Count
On Error Resume Next ' only some of these may be present
nRow = 0: nRow = CDbl(collAnswers(lAnswer)("row"))
nCol = 0: nCol = CDbl(collAnswers(lAnswer)("col"))
nCol_choice = 0: nCol_choice = CDbl(collAnswers(lAnswer)("col_choice"))
sText = "": sText = collAnswers(lAnswer)("text")
nValue = 0: nValue = Val(sText)
On Error GoTo 0
and save all those values in a recordset or sheet or whatever
Hope that helps.
I access the SM API in straight VBA.
Just CreateObject("MSXML2.XMLHTTP") then issue calls and use the SimpleJsON JSONLib to parse it.
If I wanted to access VB.Net code, I'd package it with ExcelDNA to create a XLL and that gives a straight Excel addin.
I would think you would need to add it into the References for your Excel project.
From the Ribbon, select, Tools, then References, then scroll through the list looking for something about SurveyMonkey API.
So encouraged by #sysmod I have tried to do something in VBA directly. I have left out the JSON for now as I am already in trouble. The below is giving me "Developer Inactive" as a result, though I have another project in VB.NET where the same key and token works fine.
Public Sub GetSMList()
Dim apiKey As String
Dim Token As String
Dim sm As Object
apiKey = "myKey"
Token = "myToken"
Set sm = CreateObject("MSXML2.XMLHTTP.6.0")
With sm
.Open "POST", "https://api.surveymonkey.net/v2/surveys/get_survey_list", False
.setRequestHeader "Authorization", "Bearer " & Token
.setRequestHeader "Content-Type", "application/json"
.send "api_key=" & apiKey
result = .responseText
End With
End Sub

Save slicer values to worksheet

Hi I having difficulty trying to cycle through the slicers to see if they are filtered or not.
My goal is to get all the selected Slicer into a worksheet so that I can apply a (High to Low) filter to the underlying pivot data so that I can pick the "Top 5 over budget" based upon the selections made in the Data Slicers.
I have the following code but get see error: Run Time Error 438’ Object doesn’t support this method
Can someone advise how I can achieve this.
Public Sub top_over_under_booked()
Dim oSi As SlicerItem
Dim oSlicercache As SlicerCache
Dim oSl As SlicerCacheLevel
Dim oPt As PivotTable
Dim oSh As Worksheet
Set target_ws = ThisWorkbook.Worksheets("Get Slicer Selections")
For Each oSlicercache In ThisWorkbook.SlicerCaches
For Each oPt In oSlicercache.PivotTables
oPt.Parent.Activate 'Slice Name
worksheet_name = UCase(oPt.Parent.Name)
If worksheet_name = UCase("Chart Analysis 5 Years") Then
column_no = 0
slicer_name = UCase(oSlicercache.Name)
Select Case UCase(oSlicercache.Name)
Case Is = "SLICER_FY1"
column_no = 1
Case Is = "SLicer_REPORT_PT_DEPT1"
column_no = 2
'There are actually loads more slicer which needs to ne ignored.
End Select
If column_no <> 0 Then
For Each oSl In ActiveWorkbook.SlicerCaches(oSlicercache.Name) ' <----- Error
For Each oSi In oSl.SlicerItems
'oSi.Selected = True
check_slicer_string = oSi.Value
'target_ws.Cells(ource_ws.Cells(65000, column_no).End(xlUp).Row + 1, column_no) = oSlicercache.Value
Next
Next
End If
oPT.Parent.Name
End If
Next
Next
End Sub
there are two different Excel's
using Microsoft.Office.Tools.Excel;
using Excel = Microsoft.Office.Interop.Excel;
EXAMPLE within ThisWorkBook.cs
public string SelectedReportCategories()
{
var selection = "";
var myTarget = this;
try
{
var caches = myTarget.SlicerCaches["Slicer_REPORT"];
foreach (Excel.SlicerItem slicerItem in caches.SlicerItems)
{
if (slicerItem.Selected)
selection = selection + " " + slicerItem.Name;
}
}
catch (Exception e)
{
ShowError("Configuration", (e.InnerException != null) ? e.InnerException.Message : e.Message);
}
return selection;
}

get a field value from a webpage - lotusscript

I need to read the field value from a webpage using lotusscript. Essentially I am planning on writing an agent to go to a specific URL, get a value from the page, and then use this value for the url it sends the user to.
Can anyone give me a pointer?
A
Update December 2019: As of Notes 10 (released in 2018) there is a NotesHTTPRequest class that does exactly the same thing as my code.
I do this all the time, it is not hard at all (on Windows). I created a class to do this, so it is very easy to implement.
Here is how you call it:
Dim internet As New RemoteHTML()
Dim html As String
html = internet.GetHTTP("http://www.texasswede.com/mypage.html")
That's it, now you just pull whatever information you want out of the html string.
Here is the class:
Option Public
Option Declare
Class RemoteHTML
Private httpObject As Variant
Public httpStatus As Integer
Public Sub New()
Set httpObject = CreateObject("MSXML2.ServerXMLHTTP")
End Sub
Public Function GetHTTP(httpURL As String) As String
Dim retries As Integer
retries = 0
Do
If retries>1 Then
Sleep 1 ' After the two first calls, introduce a 1 second delay betwen each additional call
End If
retries = retries + 1
Call httpObject.open("GET", httpURL, False)
Call httpObject.send()
httpStatus = httpObject.Status
If retries >= 10 Then
httpStatus = 0 ' Timeout
End If
Loop Until httpStatus = 200 Or httpStatus > 500 Or httpStatus = 404 Or httpStatus = 0
If httpStatus = 200 Then
GetHTTP = Left$(httpObject.responseText,16000)
Else
GetHTTP = ""
End If
End Function
Public Function GetFile(httpURL As String, filename As String) As Boolean
Dim session As New NotesSession
Dim retries As Integer
Dim stream As NotesStream
Dim flag As Boolean
Dim responsebody As variant
Dim cnt As Long
Dim buffer As String
Dim tmp As Byte
Set stream = session.CreateStream
retries = 0
Do
If retries>1 Then
Sleep 1 ' After the two first calls, introduce a 1 second delay betwen each additional call
End If
retries = retries + 1
Call httpObject.open("GET", httpURL, False)
Call httpObject.send()
httpStatus = httpObject.Status
If retries >= 10 Then
httpStatus = 0 ' Timeout
End If
Loop Until httpStatus = 200 Or httpStatus > 500 Or httpStatus = 404 Or httpStatus = 0
If httpStatus = 200 Then
flag = stream.Open(filename, "binary")
If flag = False Then
MsgBox "Failed to create " & filename & "..."
GetFile = False
Exit function
End If
responsebody = httpObject.ResponseBody
ForAll r in responsebody
tmp = r
Call Stream.Write(Chr$(CInt(tmp)))
cnt = cnt + 1
End ForAll
MsgBox cnt
GetFile = True
Else
GetFile = False
End If
End Function
Private Function getString(ByVal StringBin As string)
Dim intCount As Long
getString =""
For intCount = 1 To LenB(StringBin)
getString = getString & Chr( Asc(MidB(StringBin, intCount, 1)) )
Next
End Function
End Class
If your code will be running on Windows, you can use either WinHTTP or XMLHTTP COM classes to read web pages. If the code will be running on any other platform, you will be better off using Java instead of LotusScript.
If You're trying to read form a NotesField, you could go for below approach. Tha Class was created to specifically handle export of RichText items into html-strings in order to find the otherwise kind-of-hidden embedded images (pasted graphics) that may exist in NotesRichText items.
The function ExportDoc() copies the html response text into a user defined field on the document at hand:
Public Class RTExporter
session As NotesSession
db As NotesDatabase
doc As NotesDocument
obj As Variant
url As String
Public Sub New()
Set Me.session = New NotesSession()
Set db = session.CurrentDatabase
Set obj = CreateObject("Microsoft.XMLHTTP")
End Sub
' Handles export from eventual NotesRichTextitems in the form of HTml
Public Function ExportDoc(hostUrl As String, doc As NotesDocument, rtFieldName As String, htmlFieldName As String)
Dim htmlString As String
url = hostUrl & Me.db.FilePath & "/0/" & doc.Universalid & "/" & rtFieldname & "?openfield&charset=utf-8
Set Me.doc = doc
htmlString = GetHtmlFromField(htmlFieldName)
Call doc.ReplaceItemValue(htmlFieldName, htmlString)
Call doc.Save(True, False)
End Function
' Get http response text and store it in <fieldname>
Private Function GetHtmlFromField(rtFieldName As String) As String
Dim html As String
On Error Goto ERH
obj.open "GET", Me.url, False, "", ""
obj.send("")
GetHtmlFromField = Trim$(obj.responseText)
Exit Function
ERH:
GetHtmlFromField = "Error " & Err & ": " & Error & " occured on line: " & Erl
End Function
End Class

Convert from .csv file to .xlsx excel file

Hi
I am using an ASP.NET application and producing a report in excel page with .csv extension. However I would like to produce it with .xlsx etension.
The code I am currently using is as follows:
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSubmit.Click
Dim sql As String
Dim strLine As String = ""
Dim attachment As String = "attachment; filename=PTW.csv"
m_sBranch = ddlBranches.SelectedValue
m_sRegion = ddlAreas.SelectedValue
Dim cnn As SqlConnection = New SqlConnection("Server=XYZ;Database=abc;Trusted_Connection=yes;")
HttpContext.Current.Response.AddHeader("content-disposition", attachment)
HttpContext.Current.Response.ContentType = "text/csv"
cnn.Open()
sql = GetReportSql(m_sBranch, m_sRegion)
Dim cmd As SqlCommand = New SqlCommand(sql, cnn)
Dim dr As SqlDataReader
dr = cmd.ExecuteReader()
HttpContext.Current.Response.Write("PTW JOBS - EXPORTED ON " + DateTime.Now)
For i = 0 To dr.FieldCount - 1
strLine = strLine & dr.GetName(i).ToString & ","
Next
HttpContext.Current.Response.Write(strLine)
Dim sb As StringBuilder = New StringBuilder()
Dim temp As String = ""
While dr.Read()
For i = 0 To dr.FieldCount - 1
temp = temp & dr.GetValue(i)
temp = temp.Replace(",", " ")
sb.Append(temp & ",")
temp = ""
Next
sb.AppendLine()
strLine = ""
End While
HttpContext.Current.Response.Write(sb.ToString())
End Sub
Any help will be highly appreciated. Thanks.
Look into the OpenXML SDK:
I understand that my example doesn't convert .csv files, but it will steer you in the right direction.
http://msdn.microsoft.com/en-us/library/bb448854(office.14).aspx
I've used it in asp.net to create xlsx documents on the fly, streamed directly to the web client:
public static System.IO.MemoryStream ConvertToExcel(DataSet ds)
{
System.IO.MemoryStream stream = new System.IO.MemoryStream();
using (SpreadsheetDocument package = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook, true))
{
package.AddWorkbookPart();
package.WorkbookPart.Workbook = new Workbook();
package.WorkbookPart.AddNewPart<WorksheetPart>();
if (ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
DataTable tbl = ds.Tables[0];
SheetData xlSheetData = new SheetData();
foreach (DataRow row in tbl.Rows)
{
Row xlRow = new Row();
foreach (DataColumn col in tbl.Columns)
{
object cellData = row[col];
Cell xlCell = null;
if (cellData != null)
{
xlCell = new Cell(new InlineString(new DocumentFormat.OpenXml.Spreadsheet.Text(cellData.ToString()))) { DataType = CellValues.InlineString };
}
else
{
xlCell = new Cell(new InlineString(new DocumentFormat.OpenXml.Spreadsheet.Text(String.Empty))) { DataType = CellValues.InlineString };
}
xlRow.Append(xlCell);
}
xlSheetData.Append(xlRow);
}
package.WorkbookPart.WorksheetParts.First().Worksheet = new Worksheet(xlSheetData);
package.WorkbookPart.WorksheetParts.First().Worksheet.Save();
// create the worksheet to workbook relation
package.WorkbookPart.Workbook.AppendChild(new Sheets());
package.WorkbookPart.Workbook.GetFirstChild<Sheets>().AppendChild(new Sheet()
{
Id = package.WorkbookPart.GetIdOfPart(package.WorkbookPart.WorksheetParts.First()),
SheetId = 1,
Name = "Sheet1"
});
package.WorkbookPart.Workbook.Save();
}
}
return stream;
}
Shariful, from what I've read (not tried yet), I believe the best method is to set your HTTP Response headers as outlined here.
In short, the key seems to be setting the content-disposition header to "attachment".
e.g.:
Content-Disposition: attachment; filename=<file name.ext>
Sorry that I haven't tested this, but in my searching for something closely related, almost every place I went suggests to use this method in order to force download dialog.

Resources