This commit is contained in:
csh 2024-01-31 09:52:10 +08:00
parent a774f57335
commit 522e52ed46
5 changed files with 171 additions and 58 deletions

View File

@ -1,4 +1,4 @@
// Version 1.5.7
// Version 1.5.8
Function TOfficeObj(n);
Begin
case lowercase(n) of

View File

@ -1,4 +1,4 @@
// Version 1.5.7
// Version 1.5.8
Type TSDocxFile = Class
///Version: V1.0 2022-09-20
///适用于 Microsoft Word docx格式文件

View File

@ -1,4 +1,4 @@
// Version 1.5.7
// Version 1.5.8
Type TSXlsxFile = Class
///Version: V1.0 2022-08-08
///适用于 Microsoft Excel? 2007 及以上版本创建的电子表格文档。支持 XLSX / XLSM / XLTM / XLTX 等多种文档格式。
@ -8,7 +8,7 @@ Type TSXlsxFile = Class
///缺省构造函数
Function Create(); overload;
Begin
init();
Init();
End;
///构造函数打开已经存在的excel文件
@ -16,7 +16,7 @@ Type TSXlsxFile = Class
///fname: string文件名
Function Create(alias, fname); overload;
Begin
init();
Init();
OpenFile(alias, fname, nil);
End;
@ -26,17 +26,12 @@ Type TSXlsxFile = Class
///passwd: string密码
Function Create(alias, fname, passwd); overload;
Begin
init();
Init();
OpenFile(alias, fname, passwd);
End;
//析构函数
Function Destory();
Begin
End;
//初始化
Function init();
Function Init();
Begin
zipfile_ := new ZipFile();
End;
@ -51,24 +46,17 @@ Type TSXlsxFile = Class
if not ifObj(zipfile_) then return array(-1, 'Create ZipFile object fail.');
if zipfile_.FilesCount() > 0 then zipfile_ := new ZipFile();
[err, errmsg] := zipfile_.Open(alias, fname, passwd);
if err=0 then Begin
workbook_ := new xlsxWorkBook(zipfile_);
workbook_.Load();
End;
if err=0 then InitVars();
return array(err, errmsg);
End;
///新建excel文件
///返回: [err, info]
///返回: [err, errmsg]
Function NewFile();
Begin
def := TOfficeTemplate('default.xlsx', true);
[err, errmsg] := zipfile_.LoadFromMem(def);
if err = 0 then
begin
workbook_ := new xlsxWorkBook(zipfile_);
workbook_.Load();
end
if err = 0 then InitVars();
return array(err, errmsg);
End;
@ -91,11 +79,7 @@ Type TSXlsxFile = Class
Function LoadFromMem(data);
Begin
[err, errmsg] := zipfile_.LoadFromMem(data);
if err = 0 then
begin
workbook_ := new xlsxWorkBook(zipfile_);
workbook_.Load();
end
if err = 0 then InitVars();
return array(err, errmsg);
End;
@ -128,9 +112,7 @@ Type TSXlsxFile = Class
Begin
sheets := workbook_.GetSheets();
for i:=0 to length(sheets)-1 do
begin
sheets[i] := class(TSXml).Utf8ToCurCodePage(sheets[i]);
end
return sheets;
End;
@ -238,6 +220,8 @@ Type TSXlsxFile = Class
Begin
sheet_name := class(TSXml).CurCodePageToUtf8(sheet);
value := class(TSXml).CurCodePageToUtf8(val);
// 处理cell设定的样式
SetCellType(sheet, axis, value, opt);
return workbook_.SetCellValue(sheet_name, axis, value, opt);
End;
@ -1012,6 +996,22 @@ Type TSXlsxFile = Class
End;
private
Function InitVars();
Begin
workbook_ := new xlsxWorkBook(zipfile_);
workbook_.Load();
style_ := new xlsxStyles(self);
End;
Function SetCellType(sheet, axis, val, opt);
Begin
if not ifarray(opt) then opt := array();
if not ifnil(opt['t']) then return;
styleid := GetCellStyle(sheet, axis);
[t, val] := style_.GetType(styleid, val);
if t then opt['t'] := t;
End;
Function getOj(sheet, objname);
Begin
sheetname := class(TSXml).CurCodePageToUtf8(sheet);
@ -1020,12 +1020,8 @@ private
o := objMgr_[ k ];
if not ifnil(o) then return o;
case objname of
'xlsxMargin':
o := class(xlsxMargin).NewObject(sheetname, self);
'xlsxComment':
o := class(xlsxComment).NewObject(sheetname, self);
'xlsxStyles':
o := class(xlsxStyles).NewObject(sheetname, self);
'xlsxChart':
return class(xlsxChart).NewObject(sheetname, self);//不缓存xlsxChart对象
'xlsxHeaderFooter':
@ -1052,5 +1048,6 @@ private
zipfile_; //压缩文件对象
workbook_; //WorkBook对象
objMgr_; //各种对象缓存、管理
style_;
End;

View File

@ -1,15 +1,29 @@
Type xlsxStyles = Class
Function Create(sheetobj, file);
Function Create(file);
Begin
sheet_ := sheetobj;
file_ := file;
styleXmlFile_ := file_.WorkBook().GetXmlFileObj('xl/styles.xml');
style_xml_file_ := file_.WorkBook().GetXmlFileObj('xl/styles.xml');
style_ := array();
Init();
End
Function Init();
Begin
style_node := style_xml_file_.FirstChildElement("styleSheet");
xfs_node := style_node.FirstChildElement("cellXfs");
xf_node := xfs_node.FirstChildElement("xf");
count := 0;
while ifObj(xf_node) do
begin
style_[inttostr(count++)] := xf_node;
xf_node := xf_node.NextElement("xf");
end
End
Function GetStyleId(style);overload;
Begin
node := styleXmlFile_.FirstChildElement('styleSheet');
node := style_xml_file_.FirstChildElement('styleSheet');
font_id := insertNode(node, 'fonts', style.Font);
border_id := insertNode(node, 'borders', style.Border);
fill_id := insertNode(node, 'fills', style.Fill);
@ -40,15 +54,16 @@ Type xlsxStyles = Class
node := node.FirstChildElement('cellXfs');
count := node.GetAttribute('count');
node.InsertEndChild(xf.Marshal());
node.SetAttribute('count', strtoint(count) + 1);
xf_node := node.InsertEndChild(xf.Marshal());
style_[count] := xf_node;
return count;
End;
Function GetStyleId(newStyle, oldStyleId);overload;
Begin
if oldStyleId = '' then return nil;
style_node := styleXmlFile_.FirstChildElement('styleSheet');
style_node := style_xml_file_.FirstChildElement('styleSheet');
cellXfs_node := style_node.FirstChildElement('cellXfs');
count := strtoint(cellXfs_node.GetAttribute('count'));
Id := strtoint(oldStyleId);
@ -89,19 +104,14 @@ Type xlsxStyles = Class
xf_node.SetAttribute('applyProtection', 1);
end
style_[inttostr(count)] := xf_node;
return inttostr(count);
End;
Function GetStyle(styleId);
Begin
if styleId = '' then return nil;
style_node := styleXmlFile_.FirstChildElement('styleSheet');
cellXfs_node := style_node.FirstChildElement('cellXfs');
count := strtoint(cellXfs_node.GetAttribute('count'));
Id := strtoint(styleId);
if Id > count-1 then return nil;
xf := getNode(cellXfs_node, 'xf', Id);
xf := style_[styleId];
if not ifObj(xf) then return nil;
attrs := xf.Attributes();
numfmt_id := trystrtoint(attrs['numFmtId'], r) ? r : 0;
font_id := trystrtoint(attrs['fontId'], r) ? r : 0;
@ -110,6 +120,7 @@ Type xlsxStyles = Class
alignment := xf.FirstChildElement('alignment');
protection := xf.FirstChildElement('protection');
style_node := style_xml_file_.FirstChildElement('styleSheet');
style := TOfficeObj('TStyle');
numFmts_node := style_node.FirstChildElement('numFmts');
fonts_node := style_node.FirstChildElement('fonts');
@ -127,12 +138,51 @@ Type xlsxStyles = Class
return style;
End;
class Function NewObject(sheetname, file);
Function GetNumFmtId(styleId);
Begin
o := file.WorkBook().GetSheetObj(sheetname);
if not ifObj(o) then return 0;
styles := new xlsxStyles(o, file);
return styles;
node := style_[styleId];
if ifnil(node) then return '0';
numfmt := node.GetAttribute("numFmtId");
return numfmt = '' ? '' : numfmt;
End;
Function GetType(styleId, value);
Begin
numfmt_id := GetNumFmtId(styleId);
if numfmt_id = '' then return array(nil, value);
numfmt_id := strtoint(numfmt_id);
if numfmt_id = 0 then return array(nil, value);
if numfmt_id >= 1 and numfmt_id <= 10 then return array('n', value);
if numfmt_id >= 11 and numfmt_id <= 26 then
begin
if ifstring(value) and (trystrtodate(value, r) or trystrtodatetime(value, r)) then return array('n', r);
t := ifstring(value) ? 's' : 'n';
return array(t, value);
end
if numfmt_id >= 27 and numfmt_id <= 34 then return array('e', value);
if numfmt_id >= 35 and numfmt_id <= 48 then return array('n', trystrtofloat(value, r) ? r : value);
if numfmt_id = 49 then return array('s', value);
if numfmt_id >= 50 and numfmt_id <= 55 then
begin
if ifstring(value) and trystrtodate(value, r) then return array('n', r);
t := ifstring(value) ? 's' : 'n';
return array(t, value);
end
if numfmt_id >= 56 and numfmt_id <= 58 then
begin
if ifstring(value) and trystrtodatetime(value, r) then return array('n', r);
t := ifstring(value) ? 's' : 'n';
return array(t, value);
end
else begin
if ifstring(value) then
begin
if trystrtodatetime(value, r) or trystrtodate(value, r) then return array('n', r);
if trystrtofloat(value, r) then return array("n", value);
return array("s", value);
end
return array("n", value);
end
End;
private
@ -286,7 +336,65 @@ private
End
private
sheet_; //XmlSheet对象
file_; //TSExcelFile对象
styleXmlFile_; //xmlFile对象
file_; //TSXlsxFile对象
style_xml_file_;
style_; // 缓存style
End;
// {*
// 也可参考: https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.numberingformat?view=openxml-3.0.1
// numfmtid为1表示数值格式即显示为整数或小数且根据系统设置或区域设置来决定小数点、千位分隔符和负数的显示方式。
// numfmtid为2表示货币格式即显示为带有货币符号的数值且根据系统设置或区域设置来决定货币符号、小数点、千位分隔符和负数的显示方式。
// numfmtid为3表示会计格式即显示为带有货币符号和千位分隔符的数值且根据系统设置或区域设置来决定货币符号、小数点和负数的显示方式。会计格式的特点是货币符号和数值之间有一定的空格且小数位数固定为2。
// numfmtid为4表示百分比格式即显示为带有百分号的数值且根据系统设置或区域设置来决定小数点和负数的显示方式。
// numfmtid为5表示千位分隔符格式即显示为带有千位分隔符的数值。
// numfmtid为6表示负数红色格式即显示为带有负号和红色字体的数值。
// numfmtid为7表示千位分隔符格式即显示为带有千位分隔符的数值且根据系统设置或区域设置来决定小数点和负数的显示方式。
// numfmtid为8表示负数红色格式即显示为带有负号和红色字体的数值且根据系统设置或区域设置来决定小数点和千位分隔符的显示方式。
// numfmtid为9表示分数格式即显示为分数形式的数值且根据系统设置或区域设置来决定负数的显示方式。分数格式的特点是分子和分母都是一位数例如1/2。
// numfmtid为10表示指数格式即显示为带有小数点和指数的数值。
// numfmtid为11表示日期时间格式即显示为年/月/日 时:分的形式。
// numfmtid为12表示时间格式即显示为时:分:秒的形式。
// numfmtid为13表示时间格式即显示为上午/下午 时:分的形式。
// numfmtid为16表示日期格式即显示为月/日/年的形式。
// numfmtid为17表示日期格式即显示为日-月-年的形式。
// numfmtid为18表示日期格式即显示为年-月-日的形式。
// numfmtid为19表示日期格式即显示为月-年的形式。
// numfmtid为20表示日期格式即显示为年-月的形式。
// numfmtid为21表示日期时间格式即显示为年/月/日 时:分:秒的形式。
// numfmtid为22表示日期时间格式即显示为年/月/日 上午/下午 时:分的形式。
// numfmtid为23表示时间格式即显示为时:分的形式,带有前导零。
// numfmtid为24表示时间格式即显示为时:分:秒的形式,带有前导零。
// numfmtid为25表示时间格式即显示为上午/下午 时:分的形式,带有前导零。
// numfmtid为26表示时间格式即显示为上午/下午 时:分:秒的形式,带有前导零。
// numfmtid为27表示错误值格式即显示为#NULL!。
// numfmtid为28表示错误值格式即显示为#DIV/0!。
// numfmtid为29表示错误值格式即显示为#VALUE!。
// numfmtid为30表示错误值格式即显示为#REF!。
// numfmtid为31表示错误值格式即显示为#NAME?。
// numfmtid为32表示错误值格式即显示为#NUM!。
// numfmtid为33表示错误值格式即显示为#N/A。
// numfmtid为34表示错误值格式即显示为#GETTING_DATA。
// numfmtid为36表示货币格式即显示为带有货币符号和负数红色的数值。
// numfmtid为38表示会计格式即显示为带有货币符号和负数红色的数值且小数位数为2。
// numfmtid为39表示会计格式即显示为带有货币符号和负数红色的数值且小数位数为0。
// numfmtid为40表示会计格式即显示为带有货币符号和负数红色的数值且小数位数为4。
// numfmtid为41表示货币格式即显示为带有货币符号和千位分隔符的数值且小数位数为2。
// numfmtid为42表示货币格式即显示为带有货币符号和千位分隔符的数值且小数位数为0。
// numfmtid为43表示货币格式即显示为带有货币符号和千位分隔符的数值且小数位数为4。
// numfmtid为44表示货币格式即显示为带有货币符号和千位分隔符的数值且负数红色且小数位数为2。
// numfmtid为45表示货币格式即显示为带有货币符号和千位分隔符的数值且负数红色且小数位数为0。
// numfmtid为46表示货币格式即显示为带有货币符号和千位分隔符的数值且负数红色且小数位数为4。
// numfmtid为47表示会计格式即显示为带有货币符号和千位分隔符的数值且小数位数为2。
// numfmtid为48表示会计格式即显示为带有货币符号和千位分隔符的数值且小数位数为0。
// numfmtid为49表示文本格式即显示为文本。
// numfmtid为50表示日期格式即显示为年/月/日的形式,带有前导零。
// numfmtid为51表示日期格式即显示为月/日/年的形式,带有前导零。
// numfmtid为52表示日期格式即显示为日-月-年的形式,带有前导零。
// numfmtid为53表示日期格式即显示为年-月-日的形式,带有前导零。
// numfmtid为54表示日期格式即显示为月-年的形式,带有前导零。
// numfmtid为55表示日期格式即显示为年-月的形式,带有前导零。
// numfmtid为56表示日期时间格式即显示为年/月/日 时:分:秒的形式,带有前导零。
// numfmtid为57表示日期时间格式即显示为年/月/日 上午/下午 时:分的形式,带有前导零。
// numfmtid为58表示日期时间格式即显示为年/月/日 上午/下午 时:分:秒的形式,带有前导零。
// *}

View File

@ -1,12 +1,20 @@
# 更新日志
## 2023-1-18
### V1.5.8
#### excel
1. 支持写入单元格内容时判断当前单元格的数据类型,并以单元格数据类型为准
## 2023-1-17
### V1.5.7
#### excel
1. 修复单元格写入浮点数数据bug如写入0.0excel某些版本打开会显示0.00000000000000000
1. 修复单元格写入浮点数数据 bug如写入 0.0excel 某些版本打开会显示 0.00000000000000000
## 2023-1-11
@ -42,7 +50,7 @@
#### excel
1. 支持写入单元格时且单元格不存在时新的单元格会沿用设置的样式ID若有设置
1. 支持写入单元格时且单元格不存在时,新的单元格会沿用设置的样式 ID若有设置
## 2023-12-1
@ -56,7 +64,7 @@
### V1.5.1
1. 支持识别图片中含有`0xffc2`段的jpg格式的大小
1. 支持识别图片中含有`0xffc2`段的 jpg 格式的大小
## 2023-11-14