网友“海”在使用fpspreadsheet时遇到读取复杂的xlsx文件会出错:
经跟踪发现运行到fpspreadsheet\source\common\xlsxooxml.pas的procedure TsSpreadOOXMLReader.ReadFromStream的ReadDefinedNames(Doc.DocumentElement.FindNode('definedNames'))这行出错,查看早期(fpspreadsheet-1.10.1)代码发现这行已注释了的,不清楚新版本为什么又加上这行。
fpspreadsheet-1.10.1版本的:
// process the workbook.xml file (1st run) XMLStream := CreateXMLStream; try if not UnzipToStream(AStream, OOXML_PATH_XL_WORKBOOK, XMLStream) then raise EFPSpreadsheetReader.CreateFmt(rsDefectiveInternalFileStructure, ['xlsx']); ReadXMLStream(Doc, XMLStream); ReadFileVersion(Doc.DocumentElement.FindNode('fileVersion')); ReadDateMode(Doc.DocumentElement.FindNode('workbookPr')); ReadWorkbookProtection(Doc.DocumentElement.FindNode('workbookProtection')); ReadSheetList(Doc.DocumentElement.FindNode('sheets')); //ReadDefinedNames(Doc.DocumentElement.FindNode('definedNames')); -- don't read here because sheets do not yet exist ReadActiveSheet(Doc.DocumentElement.FindNode('bookViews'), actSheetIndex); FreeAndNil(Doc); finally XMLStream.Free; end;
fpspreadsheet-1.17:
// process the workbook.xml file (1st run) XMLStream := CreateXMLStream; try if not UnzipToStream(AStream, OOXML_PATH_XL_WORKBOOK, XMLStream) then raise EFPSpreadsheetReader.CreateFmt(rsDefectiveInternalFileStructure, ['xlsx']); ReadXMLStream(Doc, XMLStream); ReadFileVersion(Doc_FindNode('fileVersion')); ReadDateMode(Doc_FindNode('workbookPr')); ReadWorkbookProtection(Doc_FindNode('workbookProtection')); ReadSheetList(Doc_FindNode('sheets')); // This creates the worksheets! ReadRels(AStream, OOXML_PATH_XL_RELS_RELS, FWorkbookRels); ReadSheetRels(AStream); ReadDefinedNames(Doc.DocumentElement.FindNode('definedNames')); ReadActiveSheet(Doc_FindNode('bookViews'), actSheetIndex); FreeAndNil(Doc); finally XMLStream.Free; end;
处理方法:
将这行注释就可以
// process the workbook.xml file (1st run) XMLStream := CreateXMLStream; try if not UnzipToStream(AStream, OOXML_PATH_XL_WORKBOOK, XMLStream) then raise EFPSpreadsheetReader.CreateFmt(rsDefectiveInternalFileStructure, ['xlsx']); ReadXMLStream(Doc, XMLStream); ReadFileVersion(Doc_FindNode('fileVersion')); ReadDateMode(Doc_FindNode('workbookPr')); ReadWorkbookProtection(Doc_FindNode('workbookProtection')); ReadSheetList(Doc_FindNode('sheets')); // This creates the worksheets! ReadRels(AStream, OOXML_PATH_XL_RELS_RELS, FWorkbookRels); ReadSheetRels(AStream); //ReadDefinedNames(Doc.DocumentElement.FindNode('definedNames')); //LBZ 2024-10-25 ReadActiveSheet(Doc_FindNode('bookViews'), actSheetIndex); FreeAndNil(Doc); finally XMLStream.Free; end;
重新编译出现另一个错误:
同样是fpspreadsheet\source\common\xlsxooxml.pas这个文件。
procedure TsSpreadOOXMLReader.ReadPageSetup的StrToInt(s)这的integer超出范围
// First page number s := GetAttrValue(ANode, 'firstPageNumber'); if s <> '' then sheet.PageLayout.StartPageNumber := StrToInt(s);
处理方法很简单:
将StrToInt改为StrToInt64就可以
// First page number s := GetAttrValue(ANode, 'firstPageNumber'); if s <> '' then sheet.PageLayout.StartPageNumber := StrToInt64(s);//lbz 2024-10-25
经上述修改后的fpspreadsheet已能正常读xlsx