XLSX: Importing tables with power query connections

If a table type is "queryTable", Excel might remove table data from the
sheet based on `removeDataOnSave` attribute. In those cases, when we
export the table to XLSX, we write empty column headers, which Excel
doesn't accept.

bug-doc: forum-es-7685.xlsx
Change-Id: Ia05dda91c0806271e1846e1512328950a048ff28
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/203050
Reviewed-by: Michael Stahl <michael.stahl@collabora.com>
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
(cherry picked from commit fa2cbdb84ad571379c183f76e66c12920e787f4d)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/204433
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Karthik Godha
2026-04-27 13:25:55 +02:00
committed by Xisco Fauli
parent bf7bd37d1c
commit 66081b8f71
5 changed files with 41 additions and 6 deletions
Binary file not shown.
+12
View File
@@ -87,6 +87,18 @@ CPPUNIT_TEST_FIXTURE(ScExportTest5, testInvalidNamedRange)
CPPUNIT_ASSERT(!xNamedRanges->hasByName(u"myname"_ustr));
}
CPPUNIT_TEST_FIXTURE(ScExportTest5, testQueryTableHeaders)
{
createScDoc("xlsx/TableEmptyHeaders.xlsx");
save(TestFilter::XLSX);
xmlDocUniquePtr pTable = parseExport(u"xl/tables/table1.xml"_ustr);
CPPUNIT_ASSERT(pTable);
assertXPath(pTable, "/x:table/x:tableColumns/x:tableColumn[1]", "name", u"Column1");
assertXPath(pTable, "/x:table/x:tableColumns/x:tableColumn[2]", "name", u"Column2");
}
CPPUNIT_TEST_FIXTURE(ScExportTest5, testExternalDefinedNameXLSX)
{
createScDoc("xlsx/tdf144397.xlsx");
+2 -2
View File
@@ -81,7 +81,7 @@ public:
TableColumn& createTableColumn();
/** Applies the columns to the passed database range. */
bool finalizeImport( ScDBData* pDBData );
bool finalizeImport( ScDBData* pDBData, bool bQueryTable );
private:
typedef RefVector< TableColumn > TableColumnVector;
@@ -99,7 +99,7 @@ public:
TableColumns& createTableColumns();
/** Applies the table columns to the passed database range. */
void finalizeImport( ScDBData* pDBData );
void finalizeImport( ScDBData* pDBData, bool bQueryTable );
private:
/** Returns the table columns object used. */
+2 -1
View File
@@ -200,7 +200,8 @@ void Table::applyAutoFilters()
void Table::applyTableColumns()
{
maTableColumns.finalizeImport( findDatabaseRangeByIndex( mnTokenIndex ));
maTableColumns.finalizeImport(findDatabaseRangeByIndex(mnTokenIndex),
maModel.mnType == XML_queryTable);
}
TableBuffer::TableBuffer( const WorkbookHelper& rHelper ) :
+25 -3
View File
@@ -24,6 +24,7 @@
#include <oox/helper/attributelist.hxx>
#include <oox/token/tokens.hxx>
#include <dbdata.hxx>
#include <document.hxx>
#include <subtotalparam.hxx>
XmlColumnPrModel::XmlColumnPrModel() :
@@ -136,7 +137,7 @@ TableColumn& TableColumns::createTableColumn()
#pragma GCC diagnostic pop
#endif
bool TableColumns::finalizeImport( ScDBData* pDBData )
bool TableColumns::finalizeImport( ScDBData* pDBData, bool bQueryTable )
{
SAL_WARN_IF( static_cast<size_t>(mnCount) != maTableColumnVector.size(), "sc.filter",
"TableColumns::finalizeImport - count attribute doesn't match number of tableColumn elements");
@@ -167,6 +168,27 @@ bool TableColumns::finalizeImport( ScDBData* pDBData )
}
pDBData->SetTableColumnNames( std::move(aNames) );
// If table type is "queryTable" and `removeDataOnSave` attribute is set to true,
// Excel removes table data from sheet including headers
// We don't support Power Query connections, fill table headers in the sheet with table data.
if (bQueryTable && pDBData->HasHeader())
{
ScRange aRange;
pDBData->GetArea(aRange);
ScDocument& rDoc = getScDocument();
const std::vector<OUString>& rNames = pDBData->GetTableColumnNames();
SCCOL nStartCol = aRange.aStart.Col();
SCROW nRow = aRange.aStart.Row();
SCTAB nTab = aRange.aStart.Tab();
for (size_t j = 0; j < rNames.size(); ++j)
{
SCCOL nCol = nStartCol + static_cast<SCCOL>(j);
OUString sHeader = rNames[j];
if (!sHeader.isEmpty() && rDoc.GetString(nCol, nRow, nTab).isEmpty())
rDoc.SetString(nCol, nRow, nTab, sHeader);
}
}
// Import subtotal parameters for columns
if (hasAnySetValue)
{
@@ -194,11 +216,11 @@ TableColumns& TableColumnsBuffer::createTableColumns()
return *xTableColumns;
}
void TableColumnsBuffer::finalizeImport( ScDBData* pDBData )
void TableColumnsBuffer::finalizeImport( ScDBData* pDBData, bool bQueryTable )
{
TableColumns* pTableColumns = getActiveTableColumns();
if ( pTableColumns )
pTableColumns->finalizeImport( pDBData );
pTableColumns->finalizeImport( pDBData, bQueryTable );
}
TableColumns* TableColumnsBuffer::getActiveTableColumns()