I am trying to export a selected range to json and repeatedly run into the same problems receiving error messages "Sub or Function not defined".
Sub PrintJson()
Dim fs As Object
Dim jsonfile
Dim rangetoexport As Range
Dim rowcounter As Long
Dim columncounter As Long
Dim linedata As String
Dim path As String
Dim fname As String
Set rangetoexport = Sheets("Marketing").Range("C6", Range("C6").End(xlDown).End(xlToRight))
path = ThisWorkbook.path & "\"
fname = "export.json"
Set fs = CreateObject("Scripting.FileSystemObject")
Set jsonfile = fs.CreateTextFile(path & fname, True)
linedata = "{""Output"": ["
jsonfile.WriteLine linedata
For rowcounter = 2 To rangetoexport.Rows.Count
linedata = ""
For columncounter = 1 To rangetoexport.Columns.Count
linedata = linedata & """" & Replace(rangetoexport.Cells(1, columncounter), """", "\""") & """" & ":" & """" _
& Replace(rangetoexport.Cells(rowcounter, columncounter), """", "\""") & """" & ","
Next
linedata = Left(linedata, Len(linedata) - 1)
If rowcounter = rangetoexport.Rows.Count Then
linedata = "{" & linedata & "}"
Else
linedata = "{" & linedata & "},"
End If
jsonfile.WriteLine linedata
Next
linedata = "]}"
jsonfile.WriteLine linedata
jsonfile.Close
Set fs = Nothing
End Sub
I am really new to VBA and just learning. But this confuses me, so any help appreciated.
Related
I found this code on the internet that creates a json file from an excel file.
http://www.excelvbamacros.in/2015/01/export-range-in-jason-format.html
This is the code:
Public Sub create_json_file()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Application.EnableEvents = False
ActiveSheet.DisplayPageBreaks = False
Dim fs As Object
Dim jsonfile
Dim rangetoexport As Range
Dim rowcounter As Long
Dim columncounter As Long
Dim linedata As String
Range("A1").Select
Selection.End(xlDown).Select
Dim lRow As Long
lRow = ActiveCell.Row
Set rangetoexport = Sheets(1).Range("A1:N" & lRow)
Set fs = CreateObject("Scripting.FileSystemObject")
Set jsonfile = fs.CreateTextFile("C:\Users\Desktop\" & "jsondata.txt", True)
linedata = "["
jsonfile.WriteLine linedata
For rowcounter = 2 To rangetoexport.Rows.Count
linedata = ""
For columncounter = 1 To rangetoexport.Columns.Count
linedata = linedata & """" & rangetoexport.Cells(1, columncounter) & """" & ":" & """" & rangetoexport.Cells(rowcounter, columncounter) & """" & ","
Next
linedata = Left(linedata, Len(linedata) - 1)
If rowcounter = rangetoexport.Rows.Count Then
linedata = "{" & linedata & "}"
Else
linedata = "{" & linedata & "},"
End If
jsonfile.WriteLine linedata
Next
linedata = "]"
jsonfile.WriteLine linedata
jsonfile.Close
Set fs = Nothing
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
Application.EnableEvents = True
ActiveSheet.DisplayPageBreaks = True
End Sub
It works perfect but my json has to have a nested json object. It needs to look like this:
{
"a": "1234",
"b": 0,
"c": true,
"d": true,
"e": 1,
"f": 24,
"g": null,
"h":
{
"j": 151.70,
"k": 1,
"l": 2,
"m": true
},
"n": null,
"y": true,
"z": -1
}
Code does this:
{
"a": "1234",
"b": 0,
"c": true,
"d": true,
"e": 1,
"f": 24,
"g": null,
"h": ""
"j": 151.70,
"k": 1,
"l": 2,
"m": true
"n": null,
"y": true,
"z": -1
}
a,b,h... these are columns and my example is just one row.
I couldn't add to the code so that it would create the "h": part. Can anyone help me?
Add another loop for sheet2 inside the one for sheet1 .
Option Explicit
Public Sub create_json_file()
Const FILENAME = "jsondata.txt"
Const FOLDER = "C:\Users\Desktop\"
Const q = """"
Dim ar1, ar2, fso, ts
Dim r As Long, c As Long, c2 As Long, lrow As Long
Dim s As String
lrow = Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row
ar1 = Sheets(1).Range("A1:K" & lrow).Value2
ar2 = Sheets(2).Range("A1:D" & lrow).Value2
' build json string
s = "[{" & vbCrLf
For r = 2 To UBound(ar1)
If r > 2 Then s = s & ",{" & vbCrLf
For c = 1 To UBound(ar1, 2)
If c > 1 Then s = s & "," & vbCrLf
s = s & q & ar1(1, c) & q & ":"
If ar1(1, c) = "h" Then
s = s & "{" & vbCrLf
For c2 = 1 To UBound(ar2, 2)
If c2 > 1 Then s = s & ","
s = s & q & ar2(1, c2) & q & ":" _
& q & ar2(r, c2) & q
Next
s = s & "}"
Else
s = s & q & ar1(r, c) & q
End If
Next
s = s & "}" & vbCrLf
Next
s = s & "]"
' write out
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.CreateTextFile(FOLDER & FILENAME, True)
ts.Write s
MsgBox lrow - 1 & " rows exported to " & FOLDER & FILENAME, vbInformation
End Sub
I am giving a spreedsheet and I need to convert into JSON.
I have the following spreadsheet as so:
In essence, I'd need to convert into like this:
{ "CompanyA": {
"Products": ["Beds", "Knifes", "Spoons"]
}, "CompanyB": {
"Products": ["Beds", "Knifes", "Spoons"],
"Sites": ["West Coast", "East Coast"]
}, "CompanyC": {
"Office": ["Los Angeles"]
}}
I tried looking at online sources, but I haven't got a good solution to what I am looking for
Here's some basic code which should point you to the right direction.
I have commented it as much as possible.
Sub GetJSONOutput()
Dim wks As Worksheet: Set wks = ActiveSheet
Dim lngLastRow As Long, i As Long, j As Long, k As Long
Dim blFirstRow As Boolean
Dim strOut As String
lngLastRow = wks.Cells.Find("*", wks.Cells(1, 1), , , , xlPrevious).Row
k = 1
For i = 1 To lngLastRow
'\\ First Element - Column A
'\\ Check for first line and build beginning style
If Len(wks.Cells(i, 1).Value) > 0 Then
If blFirstRow = False Then
strOut = "{ """ & wks.Cells(i, 1).Value & """: {"
blFirstRow = True
Else '\\ Rest follow the same style
strOut = "}, """ & wks.Cells(i, 1).Value & """: {"
End If
wks.Cells(k, 4).Value = strOut: k = k + 1 '--> Output Column D
End If
'\\ Middle element - Column B
If Len(wks.Cells(i, 2).Value) > 0 Then strbase = " """ & wks.Cells(i, 2).Value & """: ["
If Len(wks.Cells(i, 3).Value) > 0 Then
'\\ Now we have Middle element then we need to loop through all elements under it!
'\\ Last Element - Column C
If Len(wks.Cells(i + 1, 3).Value) > 0 Then
strAppend = ""
For j = i To wks.Cells(i, 3).End(xlDown).Row
strAppend = strAppend & "|" & wks.Cells(j, 3).Value
Next j
strOut = strbase & """" & Replace(Mid(strAppend, 2, Len(strAppend)), "|", Chr(34) & ", " & Chr(34)) & """]"
wks.Cells(k, 4).Value = strOut: k = k + 1 '--> Output Column D
i = j - 1
Else
strOut = strbase & """" & wks.Cells(i, 3).Value & """]"
wks.Cells(k, 4).Value = strOut: k = k + 1 '--> Output Column D
End If
End If
'\\ Complete output by outputting the last closing brackets
If i = lngLastRow Then
strOut = "}}"
wks.Cells(k, 4).Value = strOut '--> Output Column D
End If
Next i
End Sub
Sub ConvertToJSONText()
Dim Sht As Worksheet
Set Sht = Worksheets("Sheet1")
Dim a As Integer
Dim lstA
Dim lstB
Dim lstC
a = 0
Dim myJsonText
myJsonText = "{"
Do While True
a = a + 1
If Sht.Range("a" & a).Value = "" And Sht.Range("b" & a).Value = "" And Sht.Range("c" & a).Value = "" Then
Exit Do
End If
If Sht.Range("a" & a).Value <> "" And Sht.Range("b" & a).Value = "" And Sht.Range("c" & a).Value = "" Then
If lstB <> "" Then myJsonText = myJsonText & "]"
If lstA <> "" Then myJsonText = myJsonText & "},"
lstA = Sht.Range("a" & a).Value
lstB = ""
lstC = ""
myJsonText = myJsonText & """" & lstA & """: {"
End If
If Sht.Range("a" & a).Value = "" And Sht.Range("b" & a).Value <> "" And Sht.Range("c" & a).Value = "" Then
If lstB <> "" Then myJsonText = myJsonText & "]"
lstB = Sht.Range("B" & a).Value
lstC = ""
myJsonText = myJsonText & """" & lstB & """: ["
End If
If Sht.Range("a" & a).Value = "" And Sht.Range("b" & a).Value = "" And Sht.Range("c" & a).Value <> "" Then
If lstC <> "" Then myJsonText = myJsonText & ","
lstC = Sht.Range("C" & a).Value
myJsonText = myJsonText & """" & lstC & """"
End If
Loop
If lstB <> "" Then myJsonText = myJsonText & "]"
myJsonText = myJsonText & "}"
End Sub
I am using this procedure to export a cell range to JSON.
Sub export_json(mysheet As Worksheet, myrange As String)
Dim fs As Object
Dim jsonfile
Dim rangetoexport As Range
Dim rowcounter As Long
Dim columncounter As Long
Dim linedata As String
Dim path As String
Dim fname As String
Set rangetoexport = mysheet.Range(myrange)
path = ThisWorkbook.path & "\"
fname = clean_filename(myrange, "") & ".json"
Set fs = CreateObject("Scripting.FileSystemObject")
Set jsonfile = fs.CreateTextFile(path & fname, True)
linedata = "{""Output"": ["
jsonfile.WriteLine linedata
For rowcounter = 2 To rangetoexport.Rows.Count
linedata = ""
For columncounter = 1 To rangetoexport.Columns.Count
linedata = linedata & """" & rangetoexport.Cells(1, columncounter) & """" & ":" & """" & rangetoexport.Cells(rowcounter, columncounter) & """" & ","
Next
linedata = Left(linedata, Len(linedata) - 1)
If rowcounter = rangetoexport.Rows.Count Then
linedata = "{" & linedata & "}"
Else
linedata = "{" & linedata & "},"
End If
jsonfile.WriteLine linedata
Next
linedata = "]}"
jsonfile.WriteLine linedata
jsonfile.Close
Set fs = Nothing
End Sub
However, if a cell value contains double quotes ", the output of JSON file becomes corrupt. Any ideas on how to fix this?
You need to escape the double quotes with a slash.
For columncounter = 1 To rangetoexport.Columns.Count
linedata = linedata & """" & Replace(rangetoexport.Cells(1, columncounter), """", "\""") & """" & ":" & """" _
& Replace(rangetoexport.Cells(rowcounter, columncounter), """", "\""") & """" & ","
Next
This answer give more details about escaping json. https://stackoverflow.com/a/19176131/7182460
I am having and issue using update batch. I have a loop that goes through a recordset updating values. I have a minimum of 333 things in the batch. When it gets to the 254th item it bails. is there a limit to a batch.
On Error GoTo Err_cmdProcessAll
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim strTableName As String
Dim strSql As String
'
Set cn = New ADODB.Connection
cn.Open "Provider=sqloledb; " & _
"Data Source=" & "BLD-FS-SQLVS04\PRDINST4" & ";" & _
"Initial Catalog=" & "HNFS_NetProv" & ";" & _
"Integrated Security=SSPI;"
cn.CursorLocation = adUseServer
Dim strSortField As String
Dim additionalwhere As String
If cboValue = "pc3Claims" Then
strTableName = "Seq3_PendedClaims_Ranked"
strSortField = "DaysSinceReceivedClaim"
' additionalwhere = " AND (member_eligibility_ud Not Like '%Program%')
strSql = "Select * " & _
"FROM " & strTableName & _
" WHERE (Complete Is Null) And (AssignedTo Is Null)" & additionalwhere & _
" ORDER BY cast( " & strSortField & " as int )" & strSort
ElseIf cboValue = "pc3ContractAssignments" Then
strSortField = "date"
additionalwhere = ""
strSql = "Select * " & _
"FROM " & strTableName & _
" WHERE (Complete Is Null) And (AssignedTo Is Null)" & additionalwhere & _
" ORDER BY CONVERT(varchar(10), CONVERT(datetime, [" & strSortField & "], 111), 121) " & strSort
End If
Set rs = New ADODB.Recordset
With rs
Set .ActiveConnection = cn
.Source = strSql
.LockType = adLockOptimistic
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.Open
End With
'make change to above to include
Dim i As Long
Dim j As Long
Dim strAssignAssociate As String
Dim lngAllocAmt As Long
For i = 1 To ListView6.ListItems.Count
If ListView6.ListItems(i).Checked Then
strAssignAssociate = ListView6.ListItems(i).SubItems(1)
Debug.Print strAssignAssociate
lngAllocAmt = ListView6.ListItems(i).Text
For j = 1 To lngAllocAmt
Debug.Print rs.Fields("AssignedTo")
rs.Fields("AssignedTo") = strAssignAssociate
Debug.Print rs.Fields("AssignedTo")
rs.MoveNext
Next j
End If
Next i
rs.UpdateBatch
MsgBox "All Finished", vbOKOnly, "Inventory Control"
Set rs = Nothing
Set cn = Nothing
I found the problem. I am using a non-keyed file. I found that I had duplicates in the file. this has been rectified and the above code works fine.
I have a list of names in a subform, and on my main form I have a button that allows the user to view the "profile" of a given contact. Once in a profile, I would like there to be a button that allows the user to move to the next name in the subform (while staying the "profile" view) by clicking "next user".
In addition, the DB asks the user whether she/he wants to save changes (vbYesNo) to the profile before moving to the next user's profile. For some reason, my code works the when the user clicks "next contact" and "yes" the first time, but it will not scroll to the next contact each subsequent time the user clicks "next contact" and "yes". Note that the "next user" button works fine if the user selects "no" for when she/he does not want to save changes made to the profile.
Here is the code:
Private Sub Command65_Click()
Dim strFirstName As String
Dim strLastName As String
Dim strIndustry As String
Dim strCountry As String
Dim strState As String
Dim strCity As String
Dim strCompany As String
Dim strTitle As String
Dim strStatus As String
Dim strPhone As String
Dim strEmail As String
Dim strOwner As String
Dim DateNow As String
Dim rs As DAO.Recordset
'Allow user to leave some fields blank. User must fill in certain fields.
Dim VisEnable
intMsg = MsgBox("Would you like to save the current contact's information?", vbYesNo)
If intMsg = 6 Then
If IsNull(Me.txtFirstName) Then
MsgBox ("Please add First Name for this Prospect")
Me.txtFirstName.SetFocus
Exit Sub
End If
If IsNull(Me.txtLastName) Then
MsgBox ("Please add Last Name for this Prospect")
Me.txtLastName.SetFocus
Exit Sub
End If
If IsNull(Me.cboIndustry) Then
Me.cboIndustry = ""
Exit Sub
End If
If IsNull(Me.cboGeo) Then
Me.cboGeo = ""
End If
If IsNull(Me.cboInfluence) Then
Me.cboInfluence = ""
End If
If IsNull(Me.cboSchool) Then
Me.cboSchool = ""
End If
If IsNull(Me.cboTier) Then
Me.cboTier = ""
End If
If IsNull(Me.cboCompany) Then
Me.cboCompany = ""
End If
If IsNull(Me.txtTitle) Then
Me.txtTitle = ""
End If
If IsNull(Me.cboStatus) Then
Me.cboStatus = ""
Exit Sub
End If
If IsNull(Me.cboOwner) Then
Me.cboOwner = ""
End If
If IsNull(Me.txtPhone) Then
Me.txtPhone = ""
End If
If IsNull(Me.txtEmail) Then
MsgBox ("Please add Email for this Prospect")
Me.txtEmail.SetFocus
Exit Sub
End If
If IsNull(Me.txtNotes) Then
Me.txtNotes = ""
Exit Sub
End If
If IsNull(Me.txtInitialProspectEmailSentDate) Then
Me.txtInitialProspectEmailSentDate = ""
End If
If IsNull(Me.txtNextTouchPoint) Then
Me.txtNextTouchPoint = ""
End If
strFirstName = Me.txtFirstName
strLastName = Me.txtLastName
strIndustry = Me.cboIndustry
strCompany = Me.cboCompany
strTitle = Me.txtTitle
strStatus = Me.cboStatus
strPhone = Me.txtPhone
strEmail = Me.txtEmail
strNotes = Me.txtNotes
strOwner = Me.cboOwner
dtEmailSent = Me.txtInitialProspectEmailSentDate
dtNextTouchPoint = Me.txtNextTouchPoint
strRegion = Me.cboGeo
strSoR = Me.cboTier
strInfluence = Me.cboInfluence
strClient = Me.ckClient
strCoworker = Me.ckCoworker
strSchool = Me.cboSchool
strSQL = "Update tblProspect Set FirstName = " & """" & strFirstName & """" & ",LastName = " & """" & strLastName & """" & ",Industry = " & """" & strIndustry & """" & "" & _
",Geography = " & """" & strRegion & """" & ",StrengthofRelationship = " & """" & strSoR & """" & ",School = " & """" & strSchool & """" & ",Company = " & """" & strCompany & """" & "" & _
",Title = " & """" & strTitle & """" & ",Status = " & """" & strStatus & """" & ", InfluenceLevel = " & """" & strInfluence & """" & ", FormerClient = " & strClient & ", FormerCoWorker = " & strCoworker & "" & _
",Email = " & """" & strEmail & """" & ",Phone = " & """" & strPhone & """" & ",ProspectOwner = " & """" & strOwner & """" & ",Notes = " & """" & strNotes & """" & ""
If dtNextTouchPoint <> "" Then
strSQL = strSQL & " ,NextTouchPoint = #" & dtNextTouchPoint & "#"
End If
If dtEmailSent <> "" Then
strSQL = strSQL & " ,LastEmailDate = #" & dtEmailSent & "#"
End If
strSQL = strSQL & " WHERE Email = " & """" & strEmail & """" & ""
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
DoCmd.SetWarnings True
intRecord = Me.txtRecord + 1
Set rs = CurrentDb.OpenRecordset("qselProspects")
If rs.RecordCount <> 0 Then
rs.MoveLast
If intRecord = 1 Then
intRecord = rs.RecordCount + 1
End If
End If
If rs.RecordCount <> 0 Then
rs.MoveFirst 'Unnecessary in this case, but still a good habit
Do Until rs.EOF = True
If intRecord = rs.AbsolutePosition Then
Me.txtRecord = intRecord
Me.txtFirstName = rs!FirstName
Me.txtLastName = rs!LastName
Me.txtTitle = rs!Title
Me.cboCompany = rs!Company
Me.cboIndustry = rs!Industry
Me.cboGeo = rs!Geography
Me.cboTier = rs!StrengthofRelationship
Me.cboIndustry = rs!InfluenceLevel
Me.cboSchool = rs!School
Me.ckClient = rs!FormerClient
Me.ckCoworker = rs!FormerCoWorker
Me.cboStatus = rs!Status
Me.cboOwner = rs!ProspectOwner
Me.txtEmail = rs!Email
Me.txtPhone = rs!Phone
Me.txtNextTouchPoint = rs!NextTouchPoint
Me.txtNotes = rs!Notes
Me.txtInitialProspectEmailSentDate = rs!LastEmailDate
End If
rs.MoveNext
Loop
End If
'''///If you choose No it works, but if you choose Yes it does not...very strange
Else
intRecord = Me.txtRecord + 1
Set rs = CurrentDb.OpenRecordset("qselProspects")
If rs.RecordCount <> 0 Then
rs.MoveLast
If rs.RecordCount = intRecord Then
intRecord = 0
End If
End If
If rs.RecordCount <> 0 Then
rs.MoveFirst
Do Until rs.EOF = True
If intRecord = rs.AbsolutePosition Then
Me.txtRecord = intRecord
Me.txtFirstName = rs!FirstName
Me.txtLastName = rs!LastName
Me.txtTitle = rs!Title
Me.cboCompany = rs!Company
Me.cboIndustry = rs!Industry
Me.cboGeo = rs!Geography
Me.cboTier = rs!StrengthofRelationship
Me.cboIndustry = rs!InfluenceLevel
Me.cboSchool = rs!School
Me.ckClient = rs!FormerClient
Me.ckCoworker = rs!FormerCoWorker
Me.cboStatus = rs!Status
Me.cboOwner = rs!ProspectOwner
Me.txtEmail = rs!Email
Me.txtPhone = rs!Phone
Me.txtNextTouchPoint = rs!NextTouchPoint
Me.txtNotes = rs!Notes
Me.txtInitialProspectEmailSentDate = rs!LastEmailDate
End If
rs.MoveNext
Loop
End If
End If
End Sub
Thanks to whoever can figure this out! This has eaten up too many hours as it is.
This is not an answer, but I write it here because it does not fit in a comment. A few advises that if you have applied, would have spared you all this head-ache.
1) your code follows the pattern
If User_Says_Yes Then
Save
Fetch_Next_Record
Else
Fetch_Next_Record
Endif
This is problematic because the Fetch_Next_Record is a lot of code and it is duplicated, and you spend a lot of time to see where it differs. duplicating code is generally a very bad idea. Try to rewrite it with the following pattern:
If User_Says_Yes Then
Save
Endif
Fetch_Next_Record
2) Try to make your code shorter, by moving as much as you can to private subroutines. for example, write some Function like BuildSQL() as String, a subroutine like updateFormFromRs(rs as Recordset). In General, when any of your routines or functions get too long, say more than 20 or 30 lines, you should think of migrating some code to subroutines and functions
3) Indent your code. It is so difficult to follow your code without it.. just to see where was the Else that starts when the user says no...
4) You fetch a whole table in the recordset, just to scroll it and find one record to display that matches if intRecord = rs.AbsolutePosition? Why not use a SQL statement with a WHERE clause and load just the desired record? This is something you need to apply in any serious application with a decent amount of data.
5) statements like If rs.EOF = True Then: Simply If rs.EOF Then.
The additional = True will not make the test more strict whatsoever. as if without it we check if the condition was almost true.
Finally, even if you have possibly inherited this code from someone else, I am sure that you will have to rewrite it completely and improve it, the sooner the better. And yes, I am sure that if you follow these guidelines, you will be able to debug you code very easily.
Friendly :)