On Ignition 8.1.24 with Reporting Module 6.1.24, a report saved as native XLS opens in Excel with gridlines off and a border on every cell that holds table data. Changing the TextShape stroke settings in the Report Designer does not change that output. The borders come from the report module's Excel exporter, not from Excel. If the downstream system needs true XLS, generate the workbook yourself with the Apache POI libraries that ship with Ignition, where you set every cell style directly.
Why don't stroke settings, CSV, or XLSX solve the border problem?
These are the usual attempts. Each one either changes the wrong stage of the chain or breaks the downstream requirement.
-
Zeroing or disabling the
TextShapestroke. Stroke is a graphic property. It controls how the shape draws in the preview and in page-based output such as PDF. The XLS exporter decides cell border formatting on its own, so stroke changes never reach the cell style records. On these versions you can change the stroke all you like and the file looks the same. - Treating it as an Excel display setting. Excel's gridline toggle is a per-sheet view flag. Cell borders are formatting saved in the file. The exported sheet already has gridlines off, which is why the borders stand out. Excel is showing what the file tells it to show.
- Switching to CSV or XLSX. Both avoid the border question, but the legacy importer accepts only XLS, so neither is an option.
- Opening and re-saving by hand in Excel. This removes the borders once. It fails on the next scheduled run and adds a manual step to an automated transfer.
Where in the export chain do the borders come from?
Follow the data from the query to the importer. The query produces a dataset. The report table binds that dataset to rows of text shapes. The XLS exporter then turns positioned shapes into worksheet cells and assigns each cell a style record. The border is part of that style record, and the exporter writes it. Nothing in the designer that sits upstream of the exporter can remove it.
| Stage | What controls it | Symptom when it is the wrong stage to adjust |
|---|---|---|
| Dataset (query/data source) | Named query, SQL query, or scripted data key | Wrong values or row count. Borders are unaffected. |
Report table / TextShape
|
Designer properties: stroke, fill, font | PDF and preview change, but the XLS borders stay. |
| XLS exporter | Reporting Module internals, not exposed as a border setting | Borders on every populated cell and gridlines off, regardless of designer settings. |
| Excel view | Sheet view flags such as gridlines | Toggling gridlines changes nothing about the borders. |
| Legacy importer | Reads BIFF cell values and may validate formatting | Rejects or misparses the file if it is sensitive to styles or types. |
How do you prove the borders are written into the file?
Check before you adjust anything. Open the exported file in Excel, select a data cell, and open Format Cells > Border. If a line style is set there, the border is stored in the file. Excel did not add it. Also confirm the file is a real binary XLS and not HTML or XML saved with an .xls extension. When Excel opens it without a file-type mismatch warning, it is a genuine XLS, which is true in this case. You can run the same check from Ignition's Script Console with POI:
from org.apache.poi.hssf.usermodel import HSSFWorkbook
from java.io import FileInputStream
fis = FileInputStream(r"C:\\exports\\report.xls")
wb = HSSFWorkbook(fis)
cell = wb.getSheetAt(0).getRow(1).getCell(0)
st = cell.getCellStyle()
print st.getBorderTop(), st.getBorderBottom(), st.getBorderLeft(), st.getBorderRight()
wb.close(); fis.close()
If any value other than NONE prints, the border is in the file. Only replacing the exporter will remove it.
How do you build the XLS with Apache POI instead of the report exporter?
Ignition includes the Apache POI libraries, and HSSFWorkbook writes the legacy binary XLS format. Excel does not need to be installed on the Gateway host. New cells get the workbook's default style, which has no borders, so you get a clean file without doing anything extra.
- Pull the same data the report uses, for example with
system.db.runNamedQueryorsystem.db.runPrepQuery, so both outputs share one source. - Create an
HSSFWorkbookand a sheet, write a header row from the column names, and write one row per dataset record. - Write numbers as numeric cells and text as string cells. Decide how to handle dates before writing: either a date-formatted cell style or a fixed string format the importer expects.
- Write the workbook to the path or share the import job reads from. Run the script from a Gateway scheduled script or from the report schedule's script action so the timing stays the same.
- Optional: load a pre-formatted
.xlstemplate withHSSFWorkbook(FileInputStream(path)), fill its data area, and save it under a new name. Use this when the importer expects fixed header text or layout.
from org.apache.poi.hssf.usermodel import HSSFWorkbook
from java.io import FileOutputStream
def write_xls(ds, path, sheet_name="Data"):
wb = HSSFWorkbook()
sh = wb.createSheet(sheet_name)
hdr = sh.createRow(0)
for c in range(ds.columnCount):
hdr.createCell(c).setCellValue(ds.getColumnName(c))
for r in range(ds.rowCount):
row = sh.createRow(r + 1)
for c in range(ds.columnCount):
v = ds.getValueAt(r, c)
if v is None:
continue
cell = row.createCell(c)
if isinstance(v, bool):
cell.setCellValue(v)
elif isinstance(v, (int, long, float)):
cell.setCellValue(float(v))
else:
cell.setCellValue(unicode(v))
fos = FileOutputStream(path)
try:
wb.write(fos)
finally:
fos.close()
wb.close()
ds = system.db.runNamedQuery("Exports/ImportData", {})
write_xls(ds, r"C:\\exports\\import.xls")
The named query path and file path above are placeholders. Replace them with your project's query and the drop location the import job uses. Scripts that run in Gateway scope write to the Gateway host's filesystem, not the designer workstation.
How do you confirm the importer receives a clean file?
- Run the read-back script from the diagnostic section against the new file. Every border side should return
NONE. - Open the file in Excel and confirm there is no file-type warning, the data cells have no borders, and the header text matches what the importer expects.
- Compare row count and a sample of values against the original report output for the same time window.
- Import one file into the legacy system before you retire the report-based export. Check that numeric columns come in as numbers and that date columns parse correctly.
What breaks when you hand-build legacy XLS files?
- Format limits. The binary XLS format caps a sheet at 65,536 rows and 256 columns. Split large exports across sheets or files before you reach those limits.
- Type drift. Writing every value as a string is simple, but older importers often expect numeric cells. Keep the type branches in the loop.
-
Gridline appearance. POI sheets show gridlines by default, while the report export hid them. Gridlines are only a view setting and never affect import. If people compare the files visually, call
sh.setDisplayGridlines(False)so the output looks the same. -
Sheet names. Excel rejects names longer than 31 characters or containing characters such as
/ \ ? * [ ]. -
Unclosed streams. If a scheduled script fails before closing the output stream, it can leave a locked or truncated file. The
try/finallyblock prevents this.
FAQ
What happens if I set the TextShape stroke width to zero in an Ignition report exported as XLS?
The preview and PDF change, but the XLS cells keep their borders. On Ignition 8.1.24 / Reporting 6.1.24, cell border formatting comes from the Excel exporter, not from shape stroke.
What happens if Excel is not installed on the Ignition Gateway server?
Nothing breaks. Apache POI reads and writes XLS and XLSX files entirely in Java, so the Gateway host does not need a copy of Excel.
What happens if the legacy system only accepts XLS but my data exceeds 65,536 rows?
A single binary XLS sheet cannot hold it. Write the data across several sheets or several files, or ask the import team whether they can ingest data in batches.
Can I keep a formatted Excel template and just fill in data from Ignition?
Yes. Open the template with HSSFWorkbook(FileInputStream(path)), write values into its data area, and save it to a new path so the template stays untouched.
What happens if POI scripting is not an option and the report exporter must produce the file?
Open a case with Inductive Automation support. Include the exact platform and Reporting Module versions (8.1.24 / 6.1.24), a sample .xls, and the report project export, and ask whether a later Reporting Module release exposes control over cell borders in XLS output.