I am using IronPython to retrieve data from an excel worksheet as follows:
import clr
clr.AddReference("Microsoft.Office.Interop.Excel")
from Microsoft.Office.Interop import Excel
filename= RunDir+filename_cfg+".xlsx"
excelApp = Excel.ApplicationClass()
excelApp.Visible = False
workbook = excelApp.Workbooks.Open(filename)
worksheet = workbook.ActiveSheet
# Find rows without comment "#", find columns without "None"
dataRows = [];
for irow in range(1,1000):
if worksheet.Cells[irow,1].Value() == None:
break
elif "#" in worksheet.Cells[irow,1].Value():
continue
else:
dataRows.append(irow)
for icol in range(1,1000):
if worksheet.Cells[dataRows[0],icol].Value() == None:
break
numCol = icol-1
cfgData = []
for irow in dataRows:
cfgData.append(worksheet.Range(worksheet.Cells[irow,1],worksheet.Cells[irow,numCol]).Value())
excelApp.Quit() #or excel.Exit()
However the data comes in as 2D array objects. I dont know how to retrieve the data from these array objects. When i've tried this in the past in a different framework this data would come in as a list and i could organize the data as i saw fit.
Is there anyway to convert this 2D array object to a list? or ensure that i retrieve a list from excel?
Thanks in advance.
Related
Scenario: I am using some functions to retrieve data from a website with VBA. These functions currently read the data into a JSON file and with some more processing paste it into a worksheet.
Issue: Having to clear and write to sheets every time a new JSON is retrieved hinders the performance of the code.
Question: Would it be possible to parse the data inside the JSON object directly into a Variant Array, so that any operations with it are done in memory?
What I already tried: following up from some research online I found Parsing Json array via VBA and http://excelerator.solutions/2017/08/16/import-json-to-excel-using-vba/ and some other pages. In all these cases, the data is parsed first into a table or directly into a worksheet, but not into an array.I tried modifying my function that writes the JSON to a sheet, by parsing through the table but that would still require me to have the "paste to worksheet" step, before reading it into an array.
Function I am working with: When I call this function, my JSON file is already retrieved and stored in memory. Also, the way this works is by iteratively parsing through each offset, which would be equivalent to the rows of the array. My idea was to skip this altogether as parse the jSON directly.:
Public Sub WriteJsonToSheet(s As Worksheet, j As JSON, Optional ByVal fields As Variant, Optional rowOffset As Long = 0)
If (rowOffset = 0) Then
Dim loopvar1 As Long, loopvar2 As Long
With s.UsedRange
.ClearFormats
.ClearContents
.ClearComments
.ClearHyperlinks
.ClearOutline
.ClearNotes
End With 's.UsedRange.Clear
End If
If j.count = 0 Then Exit Sub
' get the list of all the fields in the -first- record
If IsMissing(fields) Then
fields = j.item("0.$").GetKeys("$.")
End If
' create a table and write to the spreadsheet
If (rowOffset = 0) Then
WriteRowToRange s.Cells(1, 1), fields
s.rows(1).AutoFilter
s.rows(1).Font.Bold = True
End If
' this is part of the original function, to paste to a worksheet
If (j.count > 0) Then
'Dim table As Variant
table = JsonArrayToTable(j, fields)
WriteTableToRange s.Cells(2 + rowOffset, 1), table
End If
End Sub
I created this to add to my code, but the code just skips this part and no action takes place:
' This is my attempt to past it directly to an array
Dim table As Variant
table = JsonArrayToTable(j)
For loopvar1 = 0 To UBound(table, 2)
'For loopvar2 = 1 To UBound(table, 2)
TEST.Cells(1, loopvar1 + 1) = table(0, loopvar1)
'Next loopvar2
Next loopvar1
OBS. The data in the JSON can differ greatly, so the idea was to create a general function that could pass a JSON into an array. In this case, the example of data would be (inside my code, this JSON is retrieved for multiple IDs. Each time one is retrieved, it is pasted to a new row of the output worksheet):
{
"Response": {
"dm": [
{
"$": {
"id": ""830778192",
"end_period": ""2023-10-25T00:00:00",
"end_period1": "2021-01-25T00:00:00",
}
}
]
}
}
I've been killing myself for days on this and I can't figure it out. I'm by no means a programmer and this is my first attempt at working with JSON.
I have a GUI that I'm writing in VB.NET which gathers information for a script. I am using JSON.NET. I have it capturing the data entered into the GUI and exporting it as a JSON file, but I now need the functionality of reading the JSON file and putting the data back into the GUI.
I'm reading the contents of the datafile like this:
Dim Json As String = File.ReadAllText(fileDlg.FileName)
Dim data As JObject = JObject.Parse(Json)
Then going through each element of the file pulling the data in like this:
AD_DomainNameTB.Text = data.SelectToken("ActiveDirectory.DomainName")
AD_FQDNTB.Text = data.SelectToken("ActiveDirectory.FQDN")
AD_DomainControllerTB.Text = data.SelectToken("ActiveDirectory.DomainController")
AD_SVCUsernameTB.Text = data.SelectToken("ActiveDirectory.SVCUsername")
AD_SVCPasswordTB.Text = data.SelectToken("ActiveDirectory.SVCPassword")
AD_BaseDNTB.Text = data.SelectToken("ActiveDirectory.BaseDN")
Now, I need to cycle through an array of Sites and Site details and enter those into a datagridview on the GUI. I know I can do a for next loop for each of the items, but I don't know how to identify the number of items in the array.
The JSON data looks like this:
{
"ActiveDirectory": {
"DomainName": "CORP",
"FQDN": "corp.company.local",
"DomainController": "DC01",
"SVCUsername": "SVC_AD",
"SVCPassword": "SuperPass1",
"BaseDN": "OU=Active,DC=CORP,DC=Ccompany,DC=Local",
"CreateOUs": true,
"CreateGPOs": true,
"Sites": [
{
"Site": "Prod",
"HSA": "True",
"HSD": "True",
"HVD": null
},
{
"Site": "Test",
"HSA": "True",
"HSD": null,
"HVD": "True"
}
]
}
}
I've looked at the documentation on the site pretty extensively, but I can't find what I'm looking for. I've tried reading it into a dataset, like https://www.newtonsoft.com/json/help/html/DeserializeDataSet.htm, and I've tried creating a Class like Deserialize json array in vb.net but this doesn't make sense to me. It's way over my head.
Any help would be greatly appreciated. Please understand, that like I said, this is extremely new to me, so I need full details (don't assume that I know anything....because I don't!!)
(Using Newtonsoft.Json.Linq)
The ActiveDirectory.Sites node is of type JArray, which has a Count property.
You could iterate over the sites like this:
Dim Sites As JArray = data.SelectToken("ActiveDirectory.Sites")
For I = 0 To Sites.Count - 1
Dim Site = Sites(I)
' use `Site` and `I` in this loop body
Next
But if you don't care about the indexes, you should use a For Each loop:
Dim Sites As JArray = data.SelectToken("ActiveDirectory.Sites")
For Each Site In Sites
' use `Site` in this loop body
Next
JObject also lets you access properties using the following property lookup syntax:
Dim ActiveDirectory = data("ActiveDirectory")
Dim Sites = ActiveDirectory("Sites")
Dim SiteCount = Sites.Count
So another way you could write it is:
For Each Site In data("ActiveDirectory")("Sites")
' use `Site` in this loop body
Next
Based on the recommendations, I've gotten the code to work as I needed.Posting the full block below:
Dim Json As String = File.ReadAllText(fileDlg.FileName)
Dim data As JObject = JObject.Parse(Json)
Dim site
Dim SiteName
Dim HSA
Dim HSD
Dim HVD
AD_DomainNameTB.Text = data.SelectToken("ActiveDirectory.DomainName")
AD_FQDNTB.Text = data.SelectToken("ActiveDirectory.FQDN")
AD_DomainControllerTB.Text = data.SelectToken("ActiveDirectory.DomainController")
AD_SVCUsernameTB.Text = data.SelectToken("ActiveDirectory.SVCUsername")
AD_SVCPasswordTB.Text = data.SelectToken("ActiveDirectory.SVBPassword")
AD_BaseDNTB.Text = data.SelectToken("ActiveDirectory.BaseDN")
AD_CreateOUsCB.Checked = data.SelectToken("ActiveDirectory.CreateOUs")
AD_CreateGPOCB.Checked = data.SelectToken("ActiveDirectory.CreateGPOs")
Dim Sites As JArray = data.SelectToken("ActiveDirectory.Sites")
For Each site In Sites
SiteName = site.item("Site").ToString()
HSA = site.item("HSA").ToString()
HSD = site.item("HSD").ToString()
HVD = site.item("HVD").ToString()
If HSA = "" Then
HSA = False
End If
If HSD = "" Then
HSD = False
End If
If HVD = "" Then
HVD = False
End If
AD_SitesDatagrid.Rows.Add({SiteName, HSA, HSD, HVD})
Next
Now, there might be a better, more efficient way of going through the data in the array, but this worked.
I want to get data in Column D behind " , " in the end of the sentence from left to right to get phrase in link bio:
[1]:( http://prntscr.com/fye9hi) "here"
Someone cant help me please ....
This is my code but it cant go like i want.
import xlrd
file_location = "C:/Users/admin/DataKH.xlsx"
wb = xlrd.open_workbook(file_location)
sheet = wb.sheet_by_index(0)
print(sheet.nrows)
print(sheet.ncols)
for rows in range(sheet.nrows):
row_0 = sheet.cell_value(rows,0)
from xlwt import Workbook
import xlwt
from xlwt import Formula
workbook = xlrd.open_workbook(file_location)
sheet = workbook.sheet_by_index(0)
data = [sheet.cell_value(row,3) for row in range(sheet.nrows)]
data1 = [sheet.cell_value(row, 4) for row in range(sheet.nrows)]
workbook = xlwt.Workbook()
sheet = workbook.add_sheet('test')
for index, value in enumerate(data):
sheet.write(index, 0, value)
for index, value in enumerate(data1):
sheet.write(index, 1 , value)
workbook.save('output.xls')
How about using split(",") method? It returns a list of phrases so you can easily iterate through it though.
#MinhTuấnNgô: I'm confused with xlrd's syntax so I switched to pandas instead.
import pandas as pd
df = pd.read_excel('SampleData.xlsx')
df['Extracted Address'] = pd.Series((cell.split(',')[-1] for cell in df['Address']), index = df.index)
Not sure what you mean by 'getting the data after the comma' but this shows a way to manipulate the cell data.
After you've finished formatting the data, you can export it back to excel using df.to_excel(<filepath>)
For xlrd, you can iterate through a specific column using this syntax:
for row in ws.col(2)[1:]:
This should skip the first row (as taken care of in the case of pandas anyway) and iterate all remaining rows.
Good Morning.
Is possible naming of variables with composition of text and another variables ?
Only for an example (not functional):
Components = "AA,BB,CC"
Values = "101,102,103"
ComponentsArr = Split(Components)
ValuesArr = Split(Values)
For i = 1 To UBound(ComponentsArr)
Let "Var" & ComponentsArr(i) = ValuesArr(i)
Next i
You might be able to use a dictionary to accomplish your purpose. You add key/value pairs to the dictionary. Then you can use the key to get the value.
Set a reference to MS Scripting runtime ('Microsoft Scripting Runtime')
Components = "AA,BB,CC"
Values = "101,102,103"
ComponentsArr = Split(Components, ",")
ValuesArr = Split(Values, ",")
Dim dict As New Scripting.Dictionary
For i = LBound(ComponentsArr) To UBound(ComponentsArr)
Call dict.Add(ComponentsArr(i), ValuesArr(i))
Next i
If dict.Exists("AA") Then
Debug.Print dict.Item("AA") 'prints 101
End If
See also: https://stackoverflow.com/a/915333/2559297
It might be easier to do it like the following:
Components = Array("AA", "BB", "CC")
Values = Array("101", "102", "103")
Then you wouldn't need ComponentsArr and ValuesArr.
For i = LBound(Components) To UBound(Components)
dict.Add(Components(i), Values(i))
Next i
Title kind of states my problem.
I'm using an Api (For Vertical Response, an email list manager) which works fine. But for a particular method returns an Array where the information I need to reference is within a Dictionary inside that Array.
Array[list_id, list_name, list_type, member_data] <- member_data being the dictionary housing all my goodies.
Best I've managed to get is the listbox outputting "com.verticalresponse.api.NVPair[]" for each member.
Code
Protected Sub GetBounces()
Dim listID As Integer = 284662333
Dim isMember As Boolean = False
Dim newSession As New loginArgs()
newSession.username = username
' Your VerticalResponse username
newSession.password = password
newSession.session_duration_minutes = "120"
Dim VRUser As New VRAPI()
Try
sessionID = VRUser.login(newSession)
Dim GetMembers As New getListMembersArgs()
Try
GetMembers.session_id = sessionID
GetMembers.list_id = listID
GetMembers.max_records = 8
Try
Dim listmembers As Array = VRUser.getListMembers(GetMembers)
lstBounces.DataSource = listmembers
lstBounces.DataValueField = ("member_data").ToString()
lstBounces.DataBind()
Catch ex As Exception
lstBounces.Text = "One: " + ex.ToString()
End Try
Catch listex As Exception
lstBounces.Text = "Two: " + listex.ToString()
End Try
Catch ex As System.Exception
lstBounces.Text = "Three: " + ex.ToString()
End Try
End Sub
Edit
I have taken the suggestion of Keith Mifsud and added a breakpoint just before the Databind. It shows me that "listmembers" has eight indices (currently only testing by searching for 8 (total list will be close to 8000, of which about 1900 are needed.))
Each of those 8 indices contains the 4 columns I am looking at, so when I use listmembers(3) as the datasource I'm really only searching the fourth result, not the member_data column...
Is there a correct way to reference the column of results?
Something like:
lstbounces.DataSource = listmembers( ,3)
But instead of that, a correct one?
I think you should set the datasource as the dictionary not the array holding it
Try
Dim listmembers As Array = VRUser.getListMembers(GetMembers)
lstBounces.DataSource = listmembers(3)
'As the datasource is a dictionary, I don't think you have to set up the display and value fields
'lstBounces.DataValueField = ("member_data").ToString()
lstBounces.DataBind()
Catch ex As Exception
lstBounces.Text = "One: " + ex.ToString()
End Try
UPDATE
Based on what the collection type (dictionary within every element of an array) I would recommend you use the .net DataView with allows for expandable rows. There are some very good tutorials which can guide you to create your view