Convert from Database / Excel / CSV to YAML data fixtures? - excel

Was wondering if there is an easy to convert structured files into YAML data fixtures for Doctrine / Symfony.
I don't see any utility with Doctrine to accept CSV.
I might just start writing something simple to do this. Is it worthwhile?

I wrote my own Macro to solve this problem & shared it. You can specify the fields in your model, fill-out the data and the YAML is generated.
The best part is that it supports Nested Data as well (based on NestedSet Doctrine Behaviour)
You can download the file from here:
http://www.prasadgupte.com/go/converting-csvexcel-data-to-doctrine-yaml-fixtures/
Hope this helps!

A quick google search came up with this: http://code.activestate.com/recipes/546518-simple-conversion-of-excel-files-into-csv-and-yaml/
Requires Python though but that shouldn't be a problem. Looks quite promising and does exactly what you need (keeping in mind that CSV files can be opened with excel like a native excel file and saved as .xls)

If you are already using the conversion macro, then you can add a function that will create a PHP script from the CSV data. So a data row for the object "Pen" like:
name type price
Pen Name, Type, Price
"Reyballs Super Point 0.5", "Ball point", 10
"Palkar Ink Pen", "Ink Pen", 25
would output:
// Object: Pen
$pen1 = new Pen();
$pen1->name = "Reyballs Super Point 0.5";
$pen1->type = "Ball point";
$pen1->price = "10";
$pen1->save();
unset($pen1);
$pen2 = new Pen();
$pen2->name = "Palkar Ink Pen";
$pen2->type = "Ink Pen";
$pen2->price = "25";
$pen2->save();
unset($pen2);
Here is the macro function:
Sub GeneratePHP()
targetSheetRow = 1
fieldNamesRow = 3
sourceSheetDataRow = fieldNamesRow + 1
earlyLoopEnd = False
counter = 0
' do not run without active sheet
If ActiveSheet.Name = "" Then
MsgBox "Please call the macro from a sheet"
End
End If
' identify sheets
Set source = ActiveSheet
' custom output sheet
targetSheetName = source.Cells(1, 12)
If targetSheetName = "" Or targetSheetName = "Output" Then
targetSheetName = "Output"
Else
On Error GoTo RTE
Set Target = Worksheets(targetSheetName)
GoTo RTS
RTE:
'MsgBox "PG" & Err.Description, Title:=Err.Source
targetSheetName = "Output"
End If
RTS:
' clear exsiting data in Target/Output sheet
Set Target = Worksheets(targetSheetName)
Target.Cells.Clear
Target.Cells.Font.Name = "Courier"
' Get no of fields in model (assume level & key always there)
noOfCols = 2
Do While source.Cells(fieldNamesRow, noOfCols + 1) <> "end"
noOfCols = noOfCols + 1
Loop
' If no field other than level & key, error
If noOfCols < 3 Then
MsgBox "No data for the records"
End
End If
' print Model name
Target.Cells(targetSheetRow, 1) = "// Object: " + source.Cells(1, 4)
targetSheetRow = targetSheetRow + 1
objClass = source.Cells(1, 4)
' Loop over data rows in source sheet
Do While source.Cells(sourceSheetDataRow, 1) <> "end"
If source.Cells(sourceSheetDataRow, 1) = "end-loop" Then
Target.Cells(targetSheetRow, 1) = "<?php endfor; ?>"
targetSheetRow = targetSheetRow + 1
earlyLoopEnd = True
GoTo NextRow
End If
' rows to skip
If source.Cells(sourceSheetDataRow, 2) = "~!~" Or source.Cells(sourceSheetDataRow, 1) = "~!~" Then
GoTo NextRow
End If
' read level
blanks = source.Cells(sourceSheetDataRow, 1)
' print key
counter = counter + 1
varName = "$" + LCase(objClass) + CStr(counter)
varDec = varName + " = new " + objClass + "();"
Target.Cells(targetSheetRow, 1) = varDec
targetSheetRow = targetSheetRow + 1
spaces = spaces + " "
spaces_count = spaces_count + 2
' print fields when value != ~!~
For clNumber = 3 To noOfCols
If CStr(source.Cells(sourceSheetDataRow, clNumber)) <> "~!~" And CStr(source.Cells(fieldNamesRow, clNumber)) <> "~!~" Then
Target.Cells(targetSheetRow, 1) = varName + "->" + source.Cells(fieldNamesRow, clNumber) + " = """ + CStr(source.Cells(sourceSheetDataRow, clNumber)) + """;"
targetSheetRow = targetSheetRow + 1
End If
Next clNumber
Target.Cells(targetSheetRow, 1) = varName + "->save();"
targetSheetRow = targetSheetRow + 1
Target.Cells(targetSheetRow, 1) = "unset(" + varName + ");"
targetSheetRow = targetSheetRow + 1
NextRow:
' go for next row in source sheet
sourceSheetDataRow = sourceSheetDataRow + 1
Loop
' Success
msg = "Data from sheet """ & source.Name & """ was converted to YAML on """ & targetSheetName & """ sheet" & vbCrLf & vbCrLf & "prasadgupte.com"
MsgBox msg
' Focus on output sheet
Sheets(targetSheetName).Select
Range("A1:A" & (targetSheetRow - 1)).Select
End Sub

You can try Data Transformer (disclaimer - I'm its developer). It converts between CSV, JSON, XML, and YML locally.
It has many conversion settings (with good defaults) so you can tailor the result for your purposes.
You can get it from the Mac App Store or the Microsoft Store.
There's not trial version, but you can ask Apple or Microsoft for a refund if it doesn't work for you!

Related

Combo box listing latest 2 folders from path

I am quite new to VBA as I have been using other programming languages.
I am trying to use a combo box to list the latest 2 folders from my path.
I have already been able to select all data from the required path as well as I have sorted this.
I need support to be able to list only the latest 2 folders based on my code but am struggling and require help.
Drivepath = Mid(ThisWorkbook.Path, 1, 2)
On Error Resume Next
filepath = Drivepath & "C:\Users\Documents\Month\" & ThisWorkbook.Sheets("Months"). ComboBox1.Value & "\"
Application.Workbooks.Open (filepath & s_workbook)
Application.Sheets(1).Activate
Dim name
ThisWorkbook.Sheets("Months"). ComboBox1.Clear
Drivepath = Mid(ThisWorkbook.Path, 1,2)
For Each name In ListDirectory(Path:=Drivepath & "C:\Users\Documents\Month”, AttrInclude:=vbDirectory, AttrExclude:=vbSystem Or vbHidden)
If Len(name) > 4 Then
If InStr(name, "list") = 0 Then ThisWorkbook.Sheets("Months"). ComboBox1.AddItem name
End If
Next name
'Sort the list
ComBoList = ThisWorkbook.Sheets("Months"). ComboBox1.List
For X = LBound(ComBoList) To UBound(ComBoList) - 1
For j = X + 1 To UBound(ComBoList)
If ComBoList(X, 0) > ComBoList(j, 0) Then
ComBoTemp = ComBoList(X, 0)
ComBoList(X, 0) = ComBoList(j, 0)
ComBoList(j, 0) = ComBoTemp
End If
Next j
Next X
hold_name = ComBoList(UBound(ComBoList), 0)
ThisWorkbook.Sheets("Months"). ComboBox1.List = ComBoList
ThisWorkbook.Sheets("Months"). ComboBox1.Value = hold_name
ListDirectory
ListDirectory function
Function ListDirectory(Path As String, AttrInclude As VbFileAttribute, Optional AttrExclude As VbFileAttribute = False) As Collection
Dim Filename As String
Dim Attribs As VbFileAttribute
Set ListDirectory = New Collection
' first call to Dir() initializes the list
Filename = Dir(Path, AttrInclude)
While Filename <> ""
Attribs = GetAttr(Path & Filename)
' to be added, a file must have the right set of attributes
If Attribs And AttrInclude And Not (Attribs And AttrExclude) Then
If Len(Filename) > 4 And InStr(Filename, "Oracle") = 0 Then
ListDirectory.Add Filename, Path & Filename
End If
' fetch next filename
Filename = Dir
Wend
End Function
Am using sorting to sort the folders as all the required folders are named the following. E.g, 201901, 201902, 201903, 201904, 201905 and etc.
I just need a solution for selecting the last 2 folders which are 202003 & 202004.
I could easily delete all the other folders from the path but am looking for a more efficient way to only display 2 of the latest folders in the combo box.
Again, I have already sorted them but once I sorted them I would like to display or select only the latest folders based on sorting them.
K = UBound(ComboList)
TwoNewest = ComboList(K) & vbcrlf & ComboList(K-1)
ComboBox1.List = split(TwoNewest,vbcrlf)
There my be better ways but that'll work

Extract to excel from Access database using vba

Basically, I want to extract one column from access base on my query in VBA.
My sample code are below, No error were found but the only thing that is working is it just open the excel file were the data from access should be copied.
'Set db = OpenDatabase("\\location\names.mdb")
Set rs = db.OpenRecordset("select first_name from customerinfo " _
& "where datehired between #" & (DTPicker1) & "# and #" & (DTPicker2) & "# ;")
If rs.RecordCount <> 0 Then
Dim x As Integer
Dim count As Integer
Dim PATH, file As String
PATH =("\\location\Extracted Data.xlsm")
file = Right$(PATH, Len(PATH) - InStrRev(PATH, "\"))
Workbooks.Open PATH
Workbooks(file).Activate
count = rs.RecordCount
For x = 2 To count
Workbooks(file).Sheets("extracted").Range("a" & x) = rs.Fields("first_name")
Next
End If'
I should have 3 result to be copied in my excel. can someone help me find what seems to be missing in my code? :(
For one, you're using .RecordCount before fully loading the recordset on a dynaset. That probably returns 1, since only 1 record has been loaded yet, making your code skip over For x = 2 To count (since that's for x=2 to 1)
Secondly, you're not actually moving the recordset.
A somewhat better approach (barring other errors I might've missed):
x = 2
Do While Not rs.EOF 'While not at the end of the recordset
Workbooks(file).Sheets("extracted").Range("a" & x) = rs.Fields("first_name")
x = x + 1
rs.MoveNext 'Move to next record
Loop

Writing CSV data to an Excel file

I am trying to read a CSV file which is semicolon separated and writing its data to an Excel file cell by cell.
My CSV data is like below:
CATALOG;NAME ;TYPE
---;---;---
test ;Mapping ;BASE
test ;RECEPIENT ;BASE
I am trying to append this data to an Excel using below VBScript code.
Set objShell = WScript.CreateObject ("WScript.Shell")
Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open(objShell.CurrentDirectory & "\" & "Data.xlsx")
'objExcel.Application.Visible = True
Set objSheet = objExcel.ActiveWorkbook.Worksheets(1)
LastRow = objSheet.UsedRange.Rows.Count
WScript.Echo "LastRow "&LastRow
'objExcel.Cells(LastRow+1, 1).Value = "Test value"
Set objFileToRead = CreateObject("Scripting.FileSystemObject").OpenTextFile(objShell.CurrentDirectory & "\" & "Output.csv",1)
Dim strLine
Do While Not objFileToRead.AtEndOfStream
strResults = objFileToRead.ReadAll
Loop
objFileToRead.Close
Set objFileToRead = Nothing
If Trim(strResults) <> "" Then
' Create an Array of the Text File
arrline = Split(strResults, vbNewLine)
'WScript.Echo UBound(arrline)
End If
For i = 0 To UBound(arrline)
Do
If i = 1 Then Exit Do
If arrline(i) = "" Then
' checks for a blank line at the end of stream
Exit For
End If
ReDim Preserve arrdata(i)
arrdata(i) = Split(arrline(i), ";")
For j = 0 To UBound(arrdata(i))
WScript.Echo Trim(arrdata(i)(j))
'objExcel.Cells(LastRow+1+i,j).Value = Trim(arrdata(i)(j))
Next
Loop While False
Next
objExcel.ActiveWorkbook.Save
objExcel.ActiveWorkbook.Close
objExcel.Application.Quit
WScript.Echo "Finished."
WScript.Quit
It is showing the csv data but throwing error
Execl.vbs(41, 6) Microsoft VBScript runtime error: Unknown runtime error
Line number 41 is
objExcel.Cells(LastRow+1+i,j).Value = Trim(arrdata(i)(j))
It works if I put some hardcoded value (5,6 ..) in place of j, but it's not taking j as variable. I can not put any value of j as the number of columns in the input CSV is unknown. Please let me know where I am making a mistake and how to resolve it.
I bet the problem lies with looping through the columns starting at an improper index, column 0. Please try adjusting this line:
For j = 0 To UBound(arrdata(i))
to be
For j = 1 To UBound(arrdata(i))
and make sure to validate that it's not overlooking real data in the far-left column!

Return cell values from a closed Excel workbook

I pull data off of a database and manually enter it into an Excel report template.
I want with VBA code to lookup an exported closed Excel file (Test.xls) with data (example in cells B1:B21).
The data in the cells B1:B21 have spaces between each line. So vertically a column would be like the following
Data1
Space
Space
Data2
....
I want this with exception of the spaces to be put into the Excel report file, and displayed horizontally (A10:"Data1",B10:"Data2",C10:"data3"...) instead of vertically.
I cannot pull data directly from the database to the Excel template for security reasons.
Private Function GetValue(path, file, sheet, ref, v)
path = "C:\Documents and Settings\sdavis\Desktop\Index\XXX\Results"
file = "test.xls"
sheet = "Sheet1"
ref = "A1:R30"
' Retrieves a value from a closed workbook
Dim arg As String
Dim p As Integer
' Make sure the file exists
If Right(path, 1) <> "\" Then path = path & "\"
If Dir(path & file) = "" Then
GetValue = "File Not Found"
Exit Function
End If
' Create the argument
arg = "'" & path & "[" & file & "]" & sheet & "'!" & _
Range(ref).Cells(v, 2).Address(, , xlR1C1)
' Execute an XLM macro
GetValue = ExecuteExcel4Macro(arg)
End Function
Sub TestGetValue()
'Declare
Dim v As Integer
'Starting Point
v = 21
'File Location
path = "C:\Documents and Settings\sdavis\Desktop\Index\XXX\Results"
file = "test"
sheet = "Sheet1"
Application.ScreenUpdating = False
For C = 1 To 15
a = Cells(5, C).Address
Cells(5, C) = GetValue(path, file, sheet, a, v)
v = v + 3
Next C
Application.ScreenUpdating = True
End Sub

Replace a number in CSV file with VBscript without replacing all text

I'm working on this code
Dim strFirm,soNumber,strValues,arrStr,strCitrix,NewText,text
strFirm = "Gray"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("cloud.csv",1,True)
Do while not objTextFile.AtEndOfStream
arrStr = Split(objTextFile.ReadLine, ",")
If arrStr(0) = strFirm Then
soNumber = arrStr(1)
Exit Do
End If
Loop
objTextFile.Close
strCitrix = soNumber + 1
MsgBox "Cloud Client " & strFirm & " is now using " & strCitrix & " Citrix licenses."
NewText = Replace(soNumber, soNumber, strCitrix)
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("cloud.csv",2,True)
objTextFile.Writeline NewText
objTextFile.Close
However when I run the code the replacement wipes out all the text on my file with the exception of the number I'm writing.
What I want it to do is to leave all the other text in place and only change the one specified variable.
Example
Client1,5
Client2,7
Client3,12
Gray,6
Client4,9
Client5,17
Client6,8
And after running the script
Client1,5
Client2,7
Client3,12
Gray,7
Client4,9
Client5,17
Client6,8
Can anyone point out what I'm doing wrong?
Thank you in advance for your help.
Your output file contains only the number you're changing, because you extract just that number from the text you read from the file:
soNumber = arrStr(1)
increment it by one:
strCitrix = soNumber + 1
replace the number in soNumber (which contains only the number anyway) with the incremented number:
NewText = Replace(soNumber, soNumber, strCitrix)
and then write only that new number back to the file:
objTextFile.Writeline NewText
To preserve those parts of the original content that you want to keep you need to write them back to the file as well, not just the modified content.
If you read the source file line-by-line (which is a good idea when processing large files, as it avoids memory exhaustion), you should write the output to a temporary file as you go:
Set inFile = objFSO.OpenTextFile("cloud.csv")
Set outFile = objFSO.OpenTextFile("cloud.csv.tmp", 2, True)
Do while not objTextFile.AtEndOfStream
line = inFile.ReadLine
arrStr = Split(line, ",")
If arrStr(0) = strFirm Then
soNumber = CInt(arrStr(1))
outFile.WriteLine arrStr(0) & "," & (soNumber + 1)
Else
outFile.WriteLine line
End If
Loop
inFile.Close
outFile.Close
and then replace the original file with the modified one:
objFSO.DeleteFile "cloud.csv", True
objFSO.MoveFile "cloud.csv.tmp", "cloud.csv"
However, if your input file is small, it's easier to just read the entire file, process it, and overwrite the file with the modified content:
text = Split(objFSO.OpenTextFile("cloud.csv").ReadAll, vbNewLine)
For i = 0 To UBound(text)
If Len(text(i)) > 0 Then
arrStr = Split(text(i), ",")
If arrStr(0) = strFirm Then
soNumber = CInt(arrStr(1))
text(i) = arrStr(0) & "," & (soNumber + 1)
End If
End If
Next
objFSO.OpenTextFile("cloud.csv", 2, True).Write Join(text, vbNewLine)
The Len(text(i)) > 0 check is for skipping over empty lines (including a trailing newline at the end of the file), because empty strings are split into empty arrays, which would in turn make the check arrStr(0) = strFirm fail with an index out of bounds error.
For short file, I'd prefer a .ReadAll()/RegExp strategy:
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim sFirma : sFirma = "Gray"
Dim sFSpec : sFSpec = "..\data\cloud.csv"
Dim sAll : sAll = oFS.OpenTextFile(sFSpec).ReadAll()
Dim reCut : Set reCut = New RegExp
reCut.Global = True
reCut.Multiline = True
reCut.Pattern = "^(" & sFirma & ",)(\d+)"
Dim oMTS : Set oMTS = reCut.Execute(sAll)
If 1 = oMTS.Count Then
oFS.CreateTextFile(sFSpec).Write reCut.Replace(sAll, "$1" & (CLng(oMTS(0).SubMatches(1)) + 1))
Else
' handle error
End If
WScript.Echo oFS.OpenTextFile(sFSpec).ReadAll()
output:
Client1,5
Client2,7
Client3,12
Gray,7
Client4,9
Client5,17
Client6,8

Resources