This article is about the automating some manual,labouros process we tired to do always. If you think this is a new thing and you don't want to read further, believe me, you miss a powerful tool which you can develop from your very own Excel files without any dependency.
So let's talk about the use case first. As my daily development I have been coding on java with spring framework. As much we do our work is mostly on java, there is some manual part we need to spend in preparing properties files or some documents which requires for configuration of your app. Recently I got a work to create configuration XML files which required my main app execution. Firstly, I don't have thought to automate it, because I'm doing it for 2 XMLs files manually for each week. Each week I'm doing 2 to 6 XML files and that piled up around 40 XMLs at the end of the 6th week. So suddenly requirements got changed and XML attributes are modified. So doing manually all these modifications for 40 XMLs isn't the solution as I'm lazy though.
First thoughts to automate Then I was trying to Automate this by creating a Java project using JAXB. But the problem I face here is, I will not maintain these XMLs after delivery. There are some Product owners has to make these changes. If I develop this tool to automate these XMLs in JAVA, I making them to install jar installations. So I need a tool to automate this without leaving from their traditional excel environment.
I was looking for some alternative and came across this hidden feature in Excel. I am not sure why they hiding this "Developer" menu item from excel ribbon by default. So after that it took some time to understand how this can be helpful for my need. Spent some time coding language of VBA. But trust me its not different from our any other language you know.
Lets dive into the implementation To get the intial peek into the output what I need , here are the XMLs I have to generate.
If you see the XMLs most of the attribute values are static and some of them are basically generate dynamically from user choice.
- First step is to find out what are the static fields and what has to be dynamic.
- Once we find out the dynamic attributes we have to make them available from some interface in excel. In my case the attributes like country, state codes and courses are pulled out and provided a place to specify them.
Once the above steps are clear we are ready to go for the coding part.
- Open your excel, Navigate to Developer tab in the top ribbon. (If you don't find it, enable it from options)
- Once you click on Developer tab you can find the Visual Basic Option in the first icon. Click on it and another window will open where we can write the code.
- Just like our functions/methods, here the keyword is sub.
- First I need to tell the script to which excel sheet it has to consider. for that, the command is Sheets("Sheet1").Select Don't worry about the commands and all, whatever the thing you want to achieve search for MS documentation you will have all commands available.
Next, I need to tell the system to store the generated files in some specific location.
'Variable declaration Dim sDir As String 'Get current directory sDir = CurDir globalDir = sDir + "\base\" MkDir globalDir 'Display output on the screen MsgBox "Files will be saved in-- " & globalDir
It will create the folder with name "base" where we can find our XMLs.
- Next, step is to repeat the process for all available rows, something like loop through the collection items in Java. For that we have to take the last filled excel row.
'To get last visible row number Dim lastRow As Long lastRow = Range("A" & Rows.Count).End(xlUp).Row 'MsgBox lastRow For currentRow = 2 To lastRow Dim id As String id = Trim(Cells(currentRow, "A").Value) pathName = globalDir + "\" + id + "\" MkDir pathName file1 = pathName + "DefaultList.xml" file2 = pathName + "DefaultPathList.xml" ../ ../ ../ Next currentRow
Above code is something like for each loop we are iterating through all the rows.
Next step is to create XML structure and get the variables we need from sheet 1. In my first XML I need only one variable.
Set objStream = CreateObject("ADODB.Stream") objStream.Charset = "iso-8859-1" objStream.Open objStream.WriteText ("<CusListItem>" & vbLf) objStream.WriteText (" <CusItem>" & vbLf) objStream.WriteText (" <Customer>Default</Customer>" & vbLf) objStream.WriteText (" <CustomerId>" + id + "<Customer/Id>" & vbLf) objStream.WriteText (" <CustomerCdItem>ACTIVE</CustomerCdItem>" & vbLf) objStream.WriteText (" <FctvFr>2020-04-12T00:00:00</FctvFr>" & vbLf) objStream.WriteText (" <ItemCd>" + id + "</ItemCd>" & vbLf) objStream.WriteText (" <ItemNm>" + id + "</ItemNm>" & vbLf) objStream.WriteText (" <ItemCdSummary>" + id + "</ItemCdSummary>" & vbLf) objStream.WriteText (" <ItemCustomerTp>HEARD</ItemCustomerTp>" & vbLf) objStream.WriteText (" <PCustomerItemIdr>CRITICAL</CustomerItemIdr>" & vbLf) objStream.WriteText (" <CustomerItemCalCd>Default</CustomerItemCalCd>" & vbLf) objStream.WriteText (" </CusItem>" & vbLf) objStream.WriteText ("</CusListItem>" & vbLf) objStream.SaveToFile file1, 2 objStream.Close
So above block defines what has to be XML file look like. If you observe 5th line, we are taking that id variable value from sheet 1
Same process for next file also but with some nested XML child elements which we are taking.
Dim countryCode As String countryCode = Trim(Cells(currentRow, "C").Value) Dim stateCode As String stateCode = Trim(Cells(currentRow, "D").Value) Dim sectionCode As String sectionCode = Trim(Cells(currentRow, "F").Value) Dim courses As String courses = Trim(Cells(currentRow, "E").Value) Dim coursesArray coursesArray = Split(courses, ",") For i = LBound(coursesArray) To UBound(coursesArray) 'MsgBox coursesArray(i) objStream.WriteText (" <ItemEndCustomerCusListItemr>" & vbLf) objStream.WriteText (" <CustomeCusListItemr>Default</CustomeCusListItemr>" & vbLf) objStream.WriteText (" <CustomerId>" + countryCode + "_" + stateCode + "_" + coursesArray(i) + "_" + sectionCode + "</CustomerId>" & vbLf) objStream.WriteText (" <CustomerNttyStsCd>ACTIVE</CustomerNttyStsCd>" & vbLf) objStream.WriteText (" <CustomerFctvItemNdPtCd>" + countryCode + "_" + stateCode + "_" + coursesArray(i) + "_" + sectionCode + "</CustomerFctvItemNdPtCd>" & vbLf) objStream.WriteText (" <CustomerNdPtNm>" + coursesArray(i) + " " + sectionCode + "</CustomerNdPtNm>" & vbLf) objStream.WriteText (" <CustomerIsFldDataPrst>true</CustomerIsFldDataPrst>" & vbLf) objStream.WriteText (" </ItemEndCustomerCusListItemr>" & vbLf) Next objStream.WriteText (" </ItemEndCustomerCusListItemr>" & vbLf) objStream.SaveToFile file2, 2 objStream.Close
- So sheet1 of my excel is like below.
So execute code once without making any changes, then you will understand the entire flow.
You can also link this script execution with external event also, like linking this to button click event for more user friendly. On Developer tab, Click on Insert and select a button from Form controls . After that you will get a pop listing all scripts/macros you created and select which one you want to link.
By doing this simple automation I reduced my work from 100 to 20. Apart from this we have recording option also, which will generate the written script automatically based on our actions performed on excel. This is very useful to generate basic code on what we want and to explore.
Let me know your thoughts in the comments.