Skip to main content

I have an Excel sheet that looks like this:2021-02-08_14-06-05I would like to be able to write out data to the table outlined in red.

However, I do not know how many rows of data I will be writing out before I run the workbench. Sometimes it will be two rows of data, other times it will be 7000+ rows of data.

 

In the instance that it will be more than the 7 rows that already exist in the template, I would like the table to expand so that I keep my formatting and I don't write over the data and tables that exist below.

 

I have tried using named ranges as outlined here but I have not been successful at even getting it to write to the correct spot that way.

 

Currently, these are the parameters for the Excel Writer that I have:

2021-02-08_14-17-022021-02-08_14-17-29But this will only start it writing out in the correct spot and then overwrite the rest of the sheet when there are more than 7 rows of records:

2021-02-08_14-18-11I currently have a work around where my template has 10000 extra blank rows in the table and then I run an Excel macro to delete all the extra blank rows after I run my FME workbench. This is not an ideal solution.

 

I know that I can use python caller to do what the Excel macro is doing so that I can run the entire process within FME. However, for company IT reasons, getting openpyxl onto my computer is not a simple task.

 

Ideally I would like to set up my template with 7 rows default (as it is above) and then FME would expand the table to accommodate extra rows as needed. Is this possible?

 

ETA: I am watching this FME Excel AMA recording from 3rd Feb, 2021 and around 11:00 @Dale Lutz​ mentions this functionality (expanding the table and preserving the data below it). However they don't go into further details 😥. There was mention of an Excel World Tour recording but I don't know how to access the resources shared in the chat from the AMA.

Hi @sammy​! I spoke to our developer about this, and it looks like this functionality isn't yet supported. Sorry, I know it was mentioned in a recent webinar, but it looks like this was a misunderstanding on our part.

As it stands, the writer does not 'insert' rows in the same way that Excel will create a new row and renumber following ones - that would require a more complex implementation, and we're unsure if the library we use even supports this.

Probably not an ideal solution for you, but you might have to break out that table into a separate sheet.

I've added this as an enhancement request in our Ideas Forum. Feel free to vote for the idea and add additional information about your requirements for this.

If there's any progress on supporting this functionality, we'll post updates on this thread and on the ideas forum. Apologies again for the mix up during the webinar!


Here is my solution using openpyxl:

ExpandTableWorkbench 

  • ExcelReader brings in the data that I want to write out to the template table.
  • StatisticsCalculator counts the total number of rows of data that I want to put into the template table.
  • PythonCaller runs the code to insert the necessary number of rows and then copy the formatting to those newly inserted rows.
  • FeatureHolder makes sure that PythonCaller completes before moving on.
  • TestFilter removes the extra blank row added in by FeatureHolder.
  • ExcelWriter writes the data out to the newly saved Excel sheet (that has the correct number of rows and correct formatting) and starts writing out to the correct column & row.

 

This is the PythonCaller (code pasted without comments because I kept getting an error with the comments in):

PythonCaller 

import fme
import fmeobjects
from openpyxl import load_workbook
from copy import copy
 
def InsertRows(feature):
    wb = load_workbook('Sample_Template.xlsx')
    ws = wb.active
    default_num_rows = 7
    table_first_row = 17
    if feature.getAttribute('_count') > default_num_rows:
        rows_to_add = feature.getAttribute('_count') - default_num_rows
    else:
        rows_to_add = 0
    insert_above_row = table_first_row + 1   
    if rows_to_add != 0:
        ws.insert_rows(insert_above_row, amount = rows_to_add)
        end_unformat_range = insert_above_row + rows_to_add
        unformat_range = range(insert_above_row, end_unformat_range, 1)
        for current_row in unformat_range: 
            col_list = b'A', 'B', 'C', 'D', 'E', 'F']
            for current_col in col_list:
                current_cell = current_col + str(current_row)
                format_cell = current_col + str(table_first_row)
                ws current_cell]._style = copy(ws format_cell]._style)
    wb.save('Sample_Template_Correct_Rows.xlsx')
    pass

 And this is what the output looks like:

FormattedOutput


You can read the template in your workspace, get row.max using statistics calculator, join/merge (1-1) with you data, calculate a row attribute that starts at (row.max+1) and use that in the writer under Row Number Attribute.

Excel row attribute


Reply