From 616858545a53ef0478e162f4a9fee147600fe4bb Mon Sep 17 00:00:00 2001 From: DavidPoetsch <77153235+DavidPoetsch@users.noreply.github.com> Date: Tue, 30 Apr 2024 08:57:04 +0100 Subject: [PATCH] Parse column width and row height (#347) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: David Pötsch --- lib/src/parser/parse.dart | 80 ++++++++++++++++++ test/excel_test.dart | 26 +++++- test/test_resources/columnWidthRowHeight.xlsx | Bin 0 -> 10326 bytes 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 test/test_resources/columnWidthRowHeight.xlsx diff --git a/lib/src/parser/parse.dart b/lib/src/parser/parse.dart index 3c0f7295..0fefe5ba 100644 --- a/lib/src/parser/parse.dart +++ b/lib/src/parser/parse.dart @@ -561,6 +561,7 @@ class Parser { }); _parseHeaderFooter(worksheet, sheetObject); + _parseColWidthsRowHeights(worksheet, sheetObject); _excel._sheets[name] = sheet; @@ -811,4 +812,83 @@ class Parser { sheetObject.headerFooter = HeaderFooter.fromXmlElement(headerFooterElement); } + + void _parseColWidthsRowHeights(XmlElement worksheet, Sheet sheetObject) { + /* parse default column width and default row height + example XML content + + */ + Iterable results; + results = worksheet.findAllElements("sheetFormatPr"); + if (results.isNotEmpty) { + results.forEach((element) { + double? defaultColWidth; + double? defaultRowHeight; + // default column width + String? widthAttribute = element.getAttribute("defaultColWidth"); + if (widthAttribute != null) { + defaultColWidth = double.tryParse(widthAttribute); + } + // default row height + String? rowHeightAttribute = element.getAttribute("defaultRowHeight"); + if (rowHeightAttribute != null) { + defaultRowHeight = double.tryParse(rowHeightAttribute); + } + + // both values valid ? + if (defaultColWidth != null && defaultRowHeight != null) { + sheetObject._defaultColumnWidth = defaultColWidth; + sheetObject._defaultRowHeight = defaultRowHeight; + } + }); + } + + /* parse custom column height + example XML content + , + , + + */ + results = worksheet.findAllElements("col"); + if (results.isNotEmpty) { + results.forEach((element) { + String? colAttribute = + element.getAttribute("min"); // i think min refers to the column + String? widthAttribute = element.getAttribute("width"); + if (colAttribute != null && widthAttribute != null) { + int? col = int.tryParse(colAttribute); + double? width = double.tryParse(widthAttribute); + if (col != null && width != null) { + col -= 1; // first col in _columnWidths is index 0 + if (col >= 0) { + sheetObject._columnWidths[col] = width; + } + } + } + }); + } + + /* parse custom row height + example XML content + + */ + results = worksheet.findAllElements("row"); + if (results.isNotEmpty) { + results.forEach((element) { + String? rowAttribute = + element.getAttribute("r"); // i think min refers to the column + String? heightAttribute = element.getAttribute("ht"); + if (rowAttribute != null && heightAttribute != null) { + int? row = int.tryParse(rowAttribute); + double? height = double.tryParse(heightAttribute); + if (row != null && height != null) { + row -= 1; // first col in _rowHeights is index 0 + if (row >= 0) { + sheetObject._rowHeights[row] = height; + } + } + } + }); + } + } } diff --git a/test/excel_test.dart b/test/excel_test.dart index 493e00bf..f94c4a63 100644 --- a/test/excel_test.dart +++ b/test/excel_test.dart @@ -402,7 +402,8 @@ void main() { new Directory('./tmp').delete(recursive: true); expect(newExcel.sheets.entries.length, equals(1)); expect(newExcel.tables['Sheet1']!.maxColumns, equals(5)); - expect(newExcel.tables['Sheet1']!.rows[0][0]!.value, equals(IntCellValue(8))); + expect( + newExcel.tables['Sheet1']!.rows[0][0]!.value, equals(IntCellValue(8))); expect( newExcel.tables['Sheet1']!.rows[0][0]!.cellStyle?.numberFormat .toString(), @@ -1028,4 +1029,27 @@ void main() { testSpannedItemsSheetValues(newSheet); }); }); + + test('Parse column width row height', () { + var file = './test/test_resources/columnWidthRowHeight.xlsx'; + var bytes = File(file).readAsBytesSync(); + var excel = Excel.decodeBytes(bytes); + Sheet? sheetObject = excel.tables['Sheet1']!; + + // should 20 with a litle bit of tolerance. + expect(sheetObject.defaultColumnWidth, greaterThan(18)); + expect(sheetObject.defaultColumnWidth, lessThan(22)); + + // should 20 with a litle bit of tolerance. + expect(sheetObject.defaultRowHeight, greaterThan(18)); + expect(sheetObject.defaultRowHeight, lessThan(22)); + + // should 40 with a litle bit of tolerance. + expect(sheetObject.getColumnWidth(1), greaterThan(38)); + expect(sheetObject.getColumnWidth(1), lessThan(42)); + + // should 40 with a litle bit of tolerance. + expect(sheetObject.getRowHeight(1), greaterThan(38)); + expect(sheetObject.getRowHeight(1), lessThan(42)); + }); } diff --git a/test/test_resources/columnWidthRowHeight.xlsx b/test/test_resources/columnWidthRowHeight.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..da7c2b8208eedcc14beeb551b1c47a6bc3f7214f GIT binary patch literal 10326 zcmeHN^;^_g`yM)m7)nWLkOt`%5G15aYRHl9MnYP;y9K1X5u_2Mq|2eZ5$XDl?z`{q zy8HbL-u?V=&NbI(o@dUSbKg%MB{>8{d;l^46#xKG0&oczpeAqt03i|pfCoT@*O9Qb zae~-5>8rWhK^*m1-K?!B-XX$2&IZ84zW?v@KfD9o@gp{!>=?a=ac5ZS<*Fo0?DBYl zU3a9sc~vNV#1hnFG@+RO4Ot`xsqe7@p3dbflU!eW+Z$tl+U3kyWi@~(w8#6Z~ud%k_D1fLPnl2P&nqo%^W zL%%B)lIeTGQu%h0UQqRT4)k)~AnE*beu$I=k8%uHt&7mXdc7bj4Eyk5k6{d!tY}&a zdTm7_re=0KNX)zxuCPi{J4}kGVN+x&%TM`zzK>z_nWxOfv&arnd(fg_^tQV2`0=wU&zi1$pFB%z!@Kol zQAqDoq2j{5crx<*6K(dXk9IBB@j!-qH!oUON#9YwUl@7e0?beSog}hF?+veDJMtU> z03ZgS!ns+o{l*hlTL()cTU*N?KJ0hSz`-0DOw0fF(-J#m(anw#a2WW}f3(#;_D<=u zz-xxU*7|uA_A1<9c`M^0QTOZA_yeBGyreI=G+ZYfgRidnzps!{J1;Oit|mono=Y39 zLkFKLYMxWPt>bJy$07)qt}J6^;~AN;R8Tbe@RX{EPsJdm%RgRChm;EJ8_h(US(t≥;A>b!95rKS89X49W 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 literal 0 HcmV?d00001