Compare commits

64 Commits
Author SHA1 Message Date
csh 19b8614c93 v1.8.8 2026-09-10 15:03:04 +08:00
csh 3df8ce2be0 v1.8.7 2026-07-30 14:05:16 +08:00
csh 6b0f11cebb v1.8.6 2026-01-16 14:32:22 +08:00
csh bbe0821f68 v1.8.5 2025-12-15 13:28:02 +08:00
csh ea528f3094 v1.8.4 2025-11-07 14:24:12 +08:00
csh 95a00e7002 v1.8.3 2025-10-30 15:58:12 +08:00
csh 2b62e4e1a5 v1.8.3 2025-10-30 15:50:10 +08:00
csh a2c3905cd0 v1.8.2 2025-10-29 15:47:51 +08:00
csh ca03e53285 v1.8.1 2025-07-22 16:35:36 +08:00
csh d57631a19a v1.8.0 2025-06-23 10:50:55 +08:00
csh c05b646104 v1.7.9 2025-02-28 13:41:23 +08:00
csh 39b7549665 v1.7.8 2025-01-22 13:58:18 +08:00
csh 93533c41a0 v1.7.7 2025-01-17 18:33:30 +08:00
csh 0f07603d73 v1.7.6 2025-01-08 15:31:04 +08:00
csh 3c16ce510a v1.7.5 2025-01-07 10:56:24 +08:00
csh 3243db0e2d v1.7.4-patch1 2024-12-23 14:17:49 +08:00
csh fdd2bd0fef v1.7.4 2024-12-23 11:07:05 +08:00
csh 2d423ca1fb v1.7.3 2024-12-05 16:37:20 +08:00
csh 0e35cc0463 v1.7.2 2024-12-04 09:50:13 +08:00
csh c7b7971d9a v1.7.1 2024-11-19 18:26:49 +08:00
csh 066a8f6562 v1.70-patch3 2024-07-31 13:30:20 +08:00
csh 9e04cc2cff v1.7.0-patch2 2024-07-26 14:11:22 +08:00
csh bb8d3591ac v1.7.0-patch1 2024-07-22 11:06:49 +08:00
csh 037cb41560 v1.7.0 2024-07-18 17:26:41 +08:00
csh 5469ca318d v1.6.9 2024-05-06 15:12:37 +08:00
csh c3432d1812 v1.6.8-patch1 2024-04-17 16:22:48 +08:00
csh 53d83f91ae v1.6.8 2024-04-12 14:14:47 +08:00
csh 893a3a928b v1.6.7-patch1 2024-03-25 10:15:28 +08:00
csh 72554969bb v1.6.7 2024-03-21 16:34:38 +08:00
csh fa8800e20d v.1.6.6-patch2 2024-03-15 10:27:28 +08:00
csh 92257c380f v1.6.6-patch1 2024-03-14 14:09:55 +08:00
csh fb22cf9b0a v1.6.6 2024-03-14 10:18:16 +08:00
csh a3df0d5df9 v1.6.5 2024-03-04 16:14:03 +08:00
csh b4ef4a531c v1.6.4 2024-03-04 14:11:34 +08:00
csh f499526f04 v1.6.3 2024-02-23 11:19:29 +08:00
csh c1a93bb16e v1.6.2 2024-02-07 15:59:35 +08:00
csh 03e101fa46 v1.6.1 2024-02-06 11:28:13 +08:00
csh 1231868aa7 v1.6.0 2024-02-05 16:15:22 +08:00
csh 6d6281229c v1.5.9 2024-01-31 17:39:37 +08:00
csh 522e52ed46 v1.5.8 2024-01-31 09:52:10 +08:00
csh a774f57335 v1.5.7-patch1 2024-01-30 18:03:53 +08:00
csh 800f91870d v1.5.7 2024-01-17 17:10:16 +08:00
csh e5d011e59b v1.5.6-patch1 2024-01-12 09:11:38 +08:00
csh d588ac67d4 v1.5.6 2024-01-11 15:00:26 +08:00
csh dc7d48c318 v1.5.5 2023-12-29 10:11:50 +08:00
csh fcb2a8e7b3 v1.5.4 2023-12-18 11:33:26 +08:00
csh 91f3c5af49 v1.5.3-patch1 2023-12-15 15:14:44 +08:00
csh c16566d2f1 v1.5.3 2023-12-11 15:48:41 +08:00
csh 3607dab833 v1.5.2-patch2 2023-12-07 14:04:28 +08:00
csh 9f660c09f6 v1.5.2-patch1 2023-12-05 15:31:49 +08:00
csh 1e9b8f3a12 v1.5.2 2023-12-01 10:42:08 +08:00
csh b617f235fa v1.5.1 2023-11-15 10:51:24 +08:00
csh ee7b7164ce v1.5.0 2023-11-14 11:38:27 +08:00
csh aab0a498c6 v1.4.9-patch2 2023-10-19 14:47:21 +08:00
csh 5172a78e3e v1.4.9-patch1 2023-10-17 16:20:41 +08:00
csh de0af521bc v1.4.9 2023-10-16 17:35:16 +08:00
csh 8cd87118d5 v1.4.8-patch1 2023-09-28 16:22:33 +08:00
csh 9c917cfb70 v1.4.8 2023-09-27 14:50:53 +08:00
csh d72d88d68a v1.4.7 2023-09-22 09:42:31 +08:00
csh 5f1064794d v1.4.6-patch3 2023-09-21 09:22:15 +08:00
csh 493691b930 v1.4.6-patch2 2023-09-20 09:14:36 +08:00
csh f3094c148c v1.4.6-patch1 2023-09-19 17:00:37 +08:00
csh addc41144e v1.4.6 2023-09-19 10:10:29 +08:00
csh 8aa050461c v1.4.5 2023-08-30 15:43:03 +08:00
39 changed files with 15003 additions and 12480 deletions
+4
View File
@@ -0,0 +1,4 @@
*.swp
*.swo
*.cmd
script.ps1
+3
View File
@@ -0,0 +1,3 @@
[submodule "funcext/TSOffice/Extensions/OfficeVba"]
path = funcext/TSOffice/Extensions/OfficeVba
url = https://git.mytsl.cn/tinysoft/OfficeVba.git
+1 -1
View File
@@ -73,7 +73,7 @@ content := docx.AddTableContent(paragraphTitle, 1, 3);
docx.AddPageBreak(content.node_); docx.AddPageBreak(content.node_);
v := docx.SaveAs('', TOfficeApi().CurCodePageToGBK('DocxFile使用帮助.docx')); v := docx.SaveAs('', 'DocxFile使用帮助.docx');
println('Test Over!\n Save {}: {},time={}秒', file, v, mtoc); println('Test Over!\n Save {}: {},time={}秒', file, v, mtoc);
//info := GetProfilerInfo(true); //info := GetProfilerInfo(true);
+25 -23
View File
@@ -1,28 +1,28 @@
path := ExtractFileDir(ExtractFileDir(PluginPath())); path := ExtractFileDir(ExtractFileDir(PluginPath()));
{$IFNDEF Win32} {$IFNDEF Win32}
path := path + '\\funcext\\TSOffice\\TSExcelFile.tsf'; path := path + '/funcext/TSOffice/TSXlsxFile.tsf';
{$ELSE} {$ELSE}
path := path + '/funcext/TSOffice/TSExcelFile.tsf'; path := path + '\\funcext\\TSOffice\\TSXlsxFile.tsf';
{$ENDIF} {$ENDIF}
funcs := LoadClassInfo(path); funcs := LoadClassInfo(path);
testing := 1; testing := 1;
file := new TSExcelFile(); file := new TSXlsxFile();
[err, errinfo] := file.NewFile(); [err, errinfo] := file.NewFile();
if err then if err then
return PrintError("NewFile", err, errinfo); return PrintError("NewFile", err, errinfo);
PrintSuccess("NewFile", testing++); PrintSuccess("NewFile", testing++);
file.SetSheetName('Sheet1', 'ExcelFile'); file.SetSheetName('Sheet1', 'XlsxFile');
PrintSuccess("SetSheetName", testing++); PrintSuccess("SetSheetName", testing++);
file.NewSheet("Functions"); file.NewSheet("Functions");
PrintSuccess("NewSheet", testing++); PrintSuccess("NewSheet", testing++);
file.SetDefaultSheet('ExcelFile'); file.SetDefaultSheet('TSXlsxFile');
richtext := TOfficeObj('TRichText'); richtext := TOfficeObj('TRichText');
txt1 := richtext.AddText('TSExcelFile类 '); txt1 := richtext.AddText('TSXlsxFile类 ');
txt1.Font.Size := 35; txt1.Font.Size := 35;
txt1.Font.Color := "FF0000"; txt1.Font.Color := "FF0000";
txt1.Font.Bold := 1; txt1.Font.Bold := 1;
@@ -34,15 +34,16 @@ txt2.Font.Bold := 1;
txt2.Font.Italic := 1; txt2.Font.Italic := 1;
txt2.Font.Color := "FFC0CB"; txt2.Font.Color := "FFC0CB";
file.SetCellRichText('ExcelFile', 'A1', richtext); file.SetCellRichText('XlsxFile', 'A1', richtext);
PrintSuccess("SetCellRichText", testing++); PrintSuccess("SetCellRichText", testing++);
[err, richText] := file.GetCellRichText('ExcelFile', 'A1'); [err, richText] := file.GetCellRichText('XlsxFile', 'A1');
if err then if err then
return PrintError("GetCellRichText", err, errinfo); return PrintError("GetCellRichText", err, errinfo);
PrintSuccess("GetCellRichText", testing++); PrintSuccess("GetCellRichText", testing++);
file.MergeCell('ExcelFile', 'A1', 'C1'); file.MergeCell('XlsxFile', 'A1', 'C1');
PrintSuccess("MergeCell", testing++); PrintSuccess("MergeCell", testing++);
file.SetRowHeight('XlsxFile', 1, 60);
style := TOfficeObj('TStyle'); style := TOfficeObj('TStyle');
@@ -65,15 +66,15 @@ style.Fill.Gradient.Stop2.Color := "E0EBF5";
styleId := file.NewStyle(style); styleId := file.NewStyle(style);
PrintSuccess("NewStyle", testing++); PrintSuccess("NewStyle", testing++);
file.SetCellStyle("ExcelFile", 'A1', 'C1', styleId); file.SetCellStyle("XlsxFile", 'A1', 'C1', styleId);
file.SetCellValue("ExcelFile", "A3", "索引"); file.SetCellValue("XlsxFile", "A3", "索引");
file.SetCellValue("ExcelFile", "B3", "函数名称"); file.SetCellValue("XlsxFile", "B3", "函数名称");
file.SetCellValue("ExcelFile", "C3", "功能"); file.SetCellValue("XlsxFile", "C3", "功能");
file.SetColWidth("ExcelFile", "A", "A", 6); file.SetColWidth("XlsxFile", "A", "A", 6);
file.SetColWidth("ExcelFile", "B", "B", 55); file.SetColWidth("XlsxFile", "B", "B", 55);
file.SetColWidth("ExcelFile", "C", "C", 100); file.SetColWidth("XlsxFile", "C", "C", 100);
file.SetCellStyle("ExcelFile", "A3", "C3", styleId); file.SetCellStyle("XlsxFile", "A3", "C3", styleId);
style2 := TOfficeObj("TStyle"); style2 := TOfficeObj("TStyle");
@@ -108,9 +109,9 @@ Begin
[err0, cell0] := file.CoordinatesToCellName(1, i+4); [err0, cell0] := file.CoordinatesToCellName(1, i+4);
[err1, cell1] := file.CoordinatesToCellName(2, i+4); [err1, cell1] := file.CoordinatesToCellName(2, i+4);
[err2, cell2] := file.CoordinatesToCellName(3, i+4); [err2, cell2] := file.CoordinatesToCellName(3, i+4);
file.SetCellValue("ExcelFile", cell0, i+1); file.SetCellValue("XlsxFile", cell0, i+1);
file.SetCellValue("ExcelFile", cell1, funcs[i]['funcname']); file.SetCellValue("XlsxFile", cell1, funcs[i]['funcname']);
file.SetCellValue("ExcelFile", cell2, funcs[i]['name']); file.SetCellValue("XlsxFile", cell2, funcs[i]['name']);
str := funcs[i]['name'] + "\nFunction " + funcs[i]['funcname'] + funcs[i]['comment']; str := funcs[i]['name'] + "\nFunction " + funcs[i]['funcname'] + funcs[i]['comment'];
arr := str2array(str, "\n"); arr := str2array(str, "\n");
@@ -130,15 +131,15 @@ Begin
hyperlink.LinkType := "location"; hyperlink.LinkType := "location";
hyperlink.LinkUrl := "Functions!" $ c1; hyperlink.LinkUrl := "Functions!" $ c1;
file.SetCellHyperLink("ExcelFile", cell1, hyperlink); file.SetCellHyperLink("XlsxFile", cell1, hyperlink);
file.SetCellStyle("ExcelFile", cell1, cell1, styleId4); file.SetCellStyle("XlsxFile", cell1, cell1, styleId4);
End End
file.SetColWidth('Functions', 'A', 'A', 120); file.SetColWidth('Functions', 'A', 'A', 120);
PrintSuccess('SetColWidth', testing++); PrintSuccess('SetColWidth', testing++);
saveName := utf8toansi("ExcelFile使用帮助.xlsx"); saveName := "XlsxFile使用帮助.xlsx";
[err, errinfo] := file.SaveAs('', saveName); [err, errinfo] := file.SaveAs('', saveName);
if err then if err then
return PrintError("SaveAs", err, errinfo); return PrintError("SaveAs", err, errinfo);
@@ -320,6 +321,7 @@ Begin
excel.SetCellValue(sheet_name, cell_1, name); excel.SetCellValue(sheet_name, cell_1, name);
excel.MergeCell(sheet_name, cell_1, cell_2); excel.MergeCell(sheet_name, cell_1, cell_2);
excel.SetCellStyle(sheet_name, cell_1, cell_2, styleid1); excel.SetCellStyle(sheet_name, cell_1, cell_2, styleid1);
excel.SetRowHeight(sheet_name, row, 25);
row++; row++;
desc_arr := obj_info[i]['Desc']; desc_arr := obj_info[i]['Desc'];
Binary file not shown.
Binary file not shown.
Binary file not shown.
+15 -6
View File
@@ -1,4 +1,4 @@
# OfficePlugin # TSOffice
TSOffice 项目:纯 TSL 代码实现 excel、word 文件读写 TSOffice 项目:纯 TSL 代码实现 excel、word 文件读写
@@ -6,27 +6,36 @@ TSOffice 项目:纯 TSL 代码实现 excel、word 文件读写
### windows ### windows
对应文件夹的dll文件按如下要求 对应文件夹的 dll 文件按如下要求
- `office_plugin` 放入 tsl 安装根目录下 Plugin 文件夹 - `office_plugin` 放入 tsl 安装根目录下 Plugin 文件夹
可选: 可选:
- `fmt_pubkrnl_plugin` 放入 tsl 安装根目录下 Plugin 文件夹,若需要执行Demo文件夹下的[ExcelHelp.tsl](./Demo/ExcelHelp.tsl)和[WordHelp.tsl](./Demo/WordHelp.tsl),需要部署改动态库 - `fmt_pubkrnl_plugin` 放入 tsl 安装根目录下 Plugin 文件夹,若需要执行 Demo 文件夹下的[XlsxHelp.tsl](./Demo/XlsxHelp.tsl)和[DocxHelp.tsl](./Demo/DocxHelp.tsl),需要部署改动态库
### Linux ### Linux
根据架构选择aarch64或x86版本将对应文件夹内容进行部署 #### Ubuntu-18.04
根据架构选择 aarch64 或 x86 版本将对应文件夹内容进行部署
- `liboffice_plugin` 放入 tsl 安装根目录下 Plugin 文件夹 - `liboffice_plugin` 放入 tsl 安装根目录下 Plugin 文件夹
## 帮助文档 ## 帮助文档
- [Excel 帮助文档](./ExcelFile使用帮助.xlsx) - [Excel 帮助文档](./XlsxFile使用帮助.xlsx)
- [Word 帮助文档](./DocxFile使用帮助.docx) - [Word 帮助文档](./DocxFile使用帮助.docx)
## 扩展
扩展模块的内容需要通过`git submodule update --init --recursive`获取,相关帮助文档在`./funcext/TSOffice/Extensions/模块名`目录下可获取
支持的扩展:
- **OfficeVba** 可通过类 Vba 方式对 office文件 进行读写操作。
## Demo ## Demo
Demo文件夹提供了一些参考的demo Demo 文件夹提供了一些参考的 demo
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+94 -23
View File
@@ -1,5 +1,4 @@
// Version 1.4.4 // Version 1.8.8
Type TSDocxFile = Class Type TSDocxFile = Class
///Version: V1.0 2022-09-20 ///Version: V1.0 2022-09-20
///适用于 Microsoft Word docx格式文件 ///适用于 Microsoft Word docx格式文件
@@ -50,7 +49,7 @@ Type TSDocxFile = Class
Begin Begin
if not ifObj(zipfile_) then return array(-1, 'Create ZipFile object fail.'); if not ifObj(zipfile_) then return array(-1, 'Create ZipFile object fail.');
if zipfile_.FilesCount() > 0 then zipfile_ := new ZipFile(); if zipfile_.FilesCount() > 0 then zipfile_ := new ZipFile();
[err, errmsg] := zipfile_.Open(alias, fname, passwd); [err, errmsg] := zipfile_.Open(alias, TOfficeApi().CurCodePageToGBK(fname), passwd);
if err=0 then Begin if err=0 then Begin
document_ := new docxDocument(zipfile_); document_ := new docxDocument(zipfile_);
End; End;
@@ -88,7 +87,7 @@ Type TSDocxFile = Class
///返回: [err, info] ///返回: [err, info]
Function SaveAs(alias, fname); Function SaveAs(alias, fname);
Begin Begin
return zipfile_.Save(alias, fname); return zipfile_.Save(alias, TOfficeApi().CurCodePageToGBK(fname));
End; End;
///另存为二进制流数据 ///另存为二进制流数据
@@ -114,7 +113,10 @@ Type TSDocxFile = Class
///返回:string ///返回:string
Function FileName(); Function FileName();
Begin Begin
return zipfile_.FileName(); file_name := zipfile_.FileName();
if TOfficeApi().IsUtf8() then
return AnsiToUTF8(file_name);
return file_name;
End; End;
///word文档所有段落 ///word文档所有段落
@@ -124,6 +126,13 @@ Type TSDocxFile = Class
return document_.Body().Paragraphs(); return document_.Body().Paragraphs();
End; End;
///word文档最后一个段落
///返回:TParagraph对象
Function LastParagraph();
Begin
return document_.Body().LastParagraph();
End;
///添加新段落 ///添加新段落
///paragraph: TParagraph对象 ///paragraph: TParagraph对象
///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加段落 ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加段落
@@ -230,10 +239,12 @@ Type TSDocxFile = Class
///插入数据表 ///插入数据表
///tbl: TTable对象 ///tbl: TTable对象
///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加表格 ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加表格
///customCell: 二维数组,自定义指定单元格的样式
/// 如:一行一列arr[0][0] := array(twtcPr, twpPr, twrPr);其中twtcPr是twtcPr对象,twpPr是twpPr对象,twrPr是twrPr对象
///返回: TTable对象 ///返回: TTable对象
Function InsertTable(tbl, posOpt); Function InsertTable(tbl, posOpt, customCell);
Begin Begin
return document_.Body().InsertTable(tbl, getPosNode(posOpt)); return document_.Body().InsertTable(tbl, getPosNode(posOpt), customCell);
End; End;
///返回CoreProperties对象 ///返回CoreProperties对象
@@ -259,6 +270,13 @@ Type TSDocxFile = Class
return document_.Body().Sections(index); return document_.Body().Sections(index);
End; End;
///获取Structured Document Tag
///返回:TSdt集合
Function Sdts();
Begin
return document_.Body().Sdts();
End;
///添加章节 ///添加章节
///sessionTDocSection对象 ///sessionTDocSection对象
///posOpt: 位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加章节 ///posOpt: 位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加章节
@@ -323,7 +341,7 @@ Type TSDocxFile = Class
///返回TChart对象 ///返回TChart对象
Function CopyExcelChart(excelFileName, excelSheetName, chartName, Width, Height, posOpt); Function CopyExcelChart(excelFileName, excelSheetName, chartName, Width, Height, posOpt);
Begin Begin
excel := new TSExcelFile(); excel := new TSXlsxFile();
[err, msg] := excel.OpenFile('', excelFileName); [err, msg] := excel.OpenFile('', excelFileName);
if err then return nil; if err then return nil;
[err, charts] := excel.GetCharts(excelSheetName); [err, charts] := excel.GetCharts(excelSheetName);
@@ -372,6 +390,26 @@ Type TSDocxFile = Class
return nil; return nil;
End; End;
///复制Word内容
///alias: string,文件目录别名
///fileName: string,文件名
///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加图片
///返回: [err, TDocxCopy对象]
///TDocxCopy.GetCopiedTable() 返回复制的对象表格数组
///TDocxCopy.GetCopiedParagraph() 返回复制对象的段落数组
///TDocxCopy.GetCopiedDrawing() 返回复制对象的图表数组
Function InsertFile(alias, fileName, posOpt);overload;
Begin
document_.AddNameSpace('w16du', 'http://schemas.microsoft.com/office/word/2023/wordml/word16du');
docxObj := new TSDocxFile();
[err, msg] := docxObj.OpenFile(alias, fileName);
if err then return array(err, msg);
copy_obj := new TDocxCopy(self, docxObj);
copy_obj.Init();
copy_obj.Copy(posOpt);
return array(0, copy_obj);
End;
///复制Word内容 ///复制Word内容
///docxObj: TSDocxFile对象 ///docxObj: TSDocxFile对象
///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加图片 ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加图片
@@ -379,11 +417,9 @@ Type TSDocxFile = Class
///TDocxCopy.GetCopiedTable() 返回复制的对象表格数组 ///TDocxCopy.GetCopiedTable() 返回复制的对象表格数组
///TDocxCopy.GetCopiedParagraph() 返回复制对象的段落数组 ///TDocxCopy.GetCopiedParagraph() 返回复制对象的段落数组
///TDocxCopy.GetCopiedDrawing() 返回复制对象的图表数组 ///TDocxCopy.GetCopiedDrawing() 返回复制对象的图表数组
Function InsertFile(alias, fileName, posOpt); Function InsertFile(docxObj, posOpt);overload;
Begin Begin
docxObj := new TSDocxFile(); document_.AddNameSpace('w16du', 'http://schemas.microsoft.com/office/word/2023/wordml/word16du');
[err, msg] := docxObj.OpenFile(alias, fileName);
if err then return array(err, msg);
copy_obj := new TDocxCopy(self, docxObj); copy_obj := new TDocxCopy(self, docxObj);
copy_obj.Init(); copy_obj.Init();
copy_obj.Copy(posOpt); copy_obj.Copy(posOpt);
@@ -504,13 +540,32 @@ Type TSDocxFile = Class
return content; return content;
End; End;
///添加自定义目录
///[posOpt: 段落位置],在posOpt之后新添加目录(否则在首页添加)
///UpperHeadingLevel:标题最高级别
///LowerHeadingLevel:标题最低级别
/// 使用 UpperHeadingLevel 属性可设置起始标题级别(最高)。例如,若要设置 TOC 域语法 {TOC \o "1-3"},可将 LowerHeadingLevel 属性设为 3,并将 UpperHeadingLevel 属性设为 1。
///因为word、wps、openoffice等软件对于页码的计算各不相同,本功能不直接设置页码,需要用相关客户端软件打开文件后,更新目录域。
Function AddCustomTableContent(posOpt, UpperHeadingLevel, LowerHeadingLevel);
Begin
content := new TTableContent(self);
node := getPosNode(posOpt);
content.CustomAdd(node, UpperHeadingLevel, LowerHeadingLevel); //标题级别
if ifObj(node) then
content.node_ := document_.Body().node_.InsertAfterChild(node, content.Marshal());
else
content.node_ := document_.Body().node_.InsertFirstChild(content.Marshal());
//AddPageBreak(content.node_);
return content;
End;
///获取全部标题列表 ///获取全部标题列表
///UpperHeadingLevel:标题最高级别 ///UpperHeadingLevel:标题最高级别
///LowerHeadingLevel:标题最低级别 ///LowerHeadingLevel:标题最低级别
///返回:array((("Level":level,"Paragraph":"object","Text":title)); ///返回:array((("Level":level,"Paragraph":"object","Text":title));
Function GetHeadingList(UpperHeadingLevel, LowerHeadingLevel); Function GetHeadingList(UpperHeadingLevel, LowerHeadingLevel);
Begin Begin
return document_.Body().GetHeadingListImpl(self, nil, UpperHeadingLevel, LowerHeadingLevel, nil, true); return document_.Body().GetHeadingListImpl(self, nil, UpperHeadingLevel, LowerHeadingLevel, nil);
End; End;
//返回Document对象 //返回Document对象
@@ -535,6 +590,17 @@ Type TSDocxFile = Class
return numberingObj_; return numberingObj_;
End; End;
///返回:TFootnotes对象
Function FootNotesObject();
Begin
if not ifObj(footnotesObj_) then
begin
footnotesObj_ := new TOfficeObj('TFootnoteBody');
footnotesObj_.InitFootnotes(self.Zip());
end
return footnotesObj_;
End;
///执行word文档内嵌tsl代码(执行内嵌脚本的环境字符集为GBK) ///执行word文档内嵌tsl代码(执行内嵌脚本的环境字符集为GBK)
///返回:[err,tslFuncCount,errArr]: err 执行错误TSL代码段次数,tslFuncCount TSL代码段总数,errArr 执行TSL错误信息(array(('code':'代码', 'err':'错误信息')) ///返回:[err,tslFuncCount,errArr]: err 执行错误TSL代码段次数,tslFuncCount TSL代码段总数,errArr 执行TSL错误信息(array(('code':'代码', 'err':'错误信息'))
Function ExecInnerTSL(); Function ExecInnerTSL();
@@ -563,16 +629,20 @@ Type TSDocxFile = Class
DocPrId_ := 0; DocPrId_ := 0;
ps := Paragraphs(); ps := Paragraphs();
for i:=0 to length(ps)-1 do Begin for i:=0 to length(ps)-1 do Begin
node := class(TSXml).GetNode(ps[i].node_, 'w:r/w:drawing/wp:inline/wp:docPr'); runs := ps[i].GetRuns();
if not ifObj(node) then for j:=0 to length(runs)-1 do Begin
node := class(TSXml).GetNode(ps[i].node_, 'w:r/w:pict/v:shape/v:textbox/w:txbxContent/wp:docPr'); node := class(TSXml).GetNode(runs[j].node_, 'w:drawing/wp:inline/wp:docPr');
if not ifObj(node) then if not ifObj(node) then
node := class(TSXml).GetNode(ps[i].node_, 'w:r/mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/wp:docPr'); node := class(TSXml).GetNode(runs[j].node_, 'w:drawing/wp:anchor/wp:docPr');
if ifObj(node) then Begin if not ifObj(node) then
id := class(TSXml).SafeStrToIntDef(node.GetAttribute('id'), 0); node := class(TSXml).GetNode(runs[j].node_, 'w:pict/v:shape/v:textbox/w:txbxContent/wp:docPr');
if id > DocPrId_ then if not ifObj(node) then
DocPrId_ := id; node := class(TSXml).GetNode(runs[j].node_, 'mc:AlternateContent/mc:Choice/w:drawing/wp:anchor/wp:docPr');
break; if ifObj(node) then Begin
id := class(TSXml).SafeStrToIntDef(node.GetAttribute('id'), 0);
if id > DocPrId_ then
DocPrId_ := id;
End;
End; End;
End; End;
End; End;
@@ -591,6 +661,7 @@ private
zipfile_; //压缩文件对象 zipfile_; //压缩文件对象
document_; //Document对象 document_; //Document对象
styleObj_; styleObj_;
footnotesObj_;
numberingObj_; numberingObj_;
DocPrId_; DocPrId_;
End; End;
+2 -2
View File
@@ -1,4 +1,4 @@
// Version 1.4.4 // Version 1.5.0
Type TSExcelFile = Class Type TSExcelFile = Class
///Version: V1.0 2022-08-08 ///Version: V1.0 2022-08-08
@@ -915,7 +915,7 @@ Type TSExcelFile = Class
///复制Sheet ///复制Sheet
///sourceSheet: 源工作表 ///sourceSheet: 源工作表
///destSheet: 目的工作表 ///destSheet: 目的工作表,如果destSheet存在,则覆盖destSheet,否则末尾新增destSheet
Function CopySheet(sourceSheet, destSheet); Function CopySheet(sourceSheet, destSheet);
Begin Begin
return workbook_.CopySheet(class(TSXml).CurCodePageToUtf8(sourceSheet), class(TSXml).CurCodePageToUtf8(destSheet)); return workbook_.CopySheet(class(TSXml).CurCodePageToUtf8(sourceSheet), class(TSXml).CurCodePageToUtf8(destSheet));
+49 -27
View File
@@ -18,25 +18,59 @@ public
return RootObj; return RootObj;
End End
Function Update(); Function Update(position);overload;
Begin Begin
if ifObj(RootObj) then Begin if ifObj(RootObj) then Begin
arr := Marshal(); arr := Marshal();
if length(arr['attributes']) or length(arr['children']) then Begin if length(arr['attributes']) or length(arr['children']) then Begin
curNode := class(TSXml).GetNode(RootObj, NodeUri); curNode := class(TSXml).GetNode(RootObj, NodeUri, position);
if ifObj(curNode) then if ifObj(curNode) then
class(TSXml).UpdateNode(curNode, arr['attributes'], arr['children']); class(TSXml).UpdateNode(curNode, arr['attributes'], arr['children']);
End; End;
End; End;
End; End;
Function HandleAttrs(); virtual; Function Update();overload;
Begin Begin
End self.Update("end");
End;
Function HandleChildren(); virtual; Function Delete();overload;
Begin Begin
End if ifObj(RootObj) then
begin
curNode := class(TSXml).GetNode(RootObj, NodeUri);
if ifObj(curNode) then curNode.DeleteChildren();
end
End;
Function Delete(name);overload;
Begin
if not ifObj(RootObj) then return false;
node := NodeUri <> '' ? class(TSXml).GetNode(RootObj, NodeUri) : RootObj;
attrs := GetAttrsEx();
lName := lowerCase(name);
r := sselect * from attrs where lName = lowerCase([0]) end;
if istable(r) then
begin
node.DeleteAttribute(r[1]);
return true;
end
children := GetChildren();
r := select * from children where lName = lowerCase(['field']) end;
if istable(r) then Begin
r := r[0];
delete_node := node.FirstChildElement(r['name']);
if ifObj(delete_node) then
begin
node.DeleteChild(delete_node);
return true;
end
End;
return false;
End;
Function GetAttrs(); virtual; Function GetAttrs(); virtual;
Begin Begin
@@ -71,27 +105,16 @@ public
children_ := nil; children_ := nil;
GetChildrenEx(); //优化为变量,减少数据COPY2022-12-10 GetChildrenEx(); //优化为变量,减少数据COPY2022-12-10
child_arr := array(); child_arr := array();
name_map := array();
len := 0; len := 0;
for i:=0 to length(children_)-1 do for i:=0 to length(children_)-1 do
begin begin
node_type := children_[i]['nodeType']; node_type := children_[i]['nodeType'];
obj := children_[i]['obj']; obj := children_[i]['obj'];
if ifnil(obj) then continue; if ifnil(obj) then continue;
//find := select thisrowindex as "rowindex_", * from child_arr where ['name'] = children_[i]['name'] end; //优化为循环,性能提高15-20%2022-12-20 if not ifObj(obj) and not ifnil(name_map[children_[i]['name']]) and children_[i]['attrEx'] <> '' then
find := array();
for j:=length(child_arr)-1 downto 0 do Begin //支持列表模式(如多节点:<w:t xml:space=""></w:t>),查找最近的节点
if child_arr[j]['name'] = children_[i]['name'] then Begin
find[0] := child_arr[j];
find[0]['rowindex_'] := j;
break;
End;
End;
if not ifnil(obj) and not ifObj(obj) and istable(find) and ifstring(children_[i]['attrEx']) and children_[i]['attrEx'] <> '' then
begin begin
if not ifarray(find[0]['attributes']) then find[0]['attributes'] := array(); child_arr[name_map[children_[i]['name']]]['attributes'] union=array(children_[i]['attrEx'] : obj);
key := children_[i]['attrEx'];
find[0]['attributes'] union= array(key : obj);
child_arr[find[0]['rowindex_']]['attributes'] := find[0]['attributes'];
continue; continue;
end end
@@ -100,7 +123,7 @@ public
begin begin
empty_name := children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; empty_name := children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val';
if obj = 0 then arr['attributes'] := array(empty_name: 0); if obj = 0 then arr['attributes'] := array(empty_name: 0);
else if obj = 1 then arr['attributes'] := array(empty_name: 1) else if obj = 1 then arr['attributes'] := array(empty_name: 1);
end end
else if node_type = 'pcdata' then else if node_type = 'pcdata' then
begin begin
@@ -118,7 +141,7 @@ public
key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val';
arr['attributes'] := array(key : obj); arr['attributes'] := array(key : obj);
end end
name_map[children_[i]['name']] := len;
child_arr[len++] := arr; child_arr[len++] := arr;
end end
@@ -154,7 +177,7 @@ public
return 1; return 1;
End End
Function Value(name); Function Value(name, nottransferable);
Begin Begin
if not ifObj(RootObj) then return nil; if not ifObj(RootObj) then return nil;
if NodeUri <> '' then if NodeUri <> '' then
@@ -169,7 +192,7 @@ public
if istable(r) then if istable(r) then
begin begin
value := node.GetAttribute(r[1]); value := node.GetAttribute(r[1]);
return trystrtofloat(value, r) ? r : value; return nottransferable ? value : trystrtofloat(value, r) ? r : value;
end end
children := GetChildren(); children := GetChildren();
@@ -177,7 +200,7 @@ public
if istable(r) then Begin if istable(r) then Begin
r := r[0]; r := r[0];
node := node.FirstChildElement(r['name']); node := node.FirstChildElement(r['name']);
if not ifObj(node) and r['nodeType'] = 'empty' then return false; if not ifObj(node) and r['nodeType'] = 'empty' and not nottransferable then return false;
if not ifObj(node) then return nil; if not ifObj(node) then return nil;
if r['nodeType'] = 'pcdata' then //返回文本串 if r['nodeType'] = 'pcdata' then //返回文本串
return node.GetText(); return node.GetText();
@@ -186,7 +209,7 @@ public
key := r['attrName'] ? r['attrName'] : r['attrEx'] ? r['attrEx'] : 'val'; key := r['attrName'] ? r['attrName'] : r['attrEx'] ? r['attrEx'] : 'val';
value := node.GetAttribute(key); value := node.GetAttribute(key);
if r['nodeType'] = 'empty' and value = '' then return true; if r['nodeType'] = 'empty' and value = '' then return true;
return trystrtofloat(value, r) ? r : value; return nottransferable ? value : trystrtofloat(value, r) ? r : value;
End; End;
return nil; return nil;
End; End;
@@ -269,7 +292,6 @@ public
NodeName; NodeName;
ExtAttr; ExtAttr;
ExtNodes; ExtNodes;
//Parent;
ReplaceArr; ReplaceArr;
RootObj; // xml node RootObj; // xml node
NodeUri:string; NodeUri:string;
+27
View File
@@ -179,6 +179,33 @@ Type TOffice = Class
return getTextBoxImpl(p, true); return getTextBoxImpl(p, true);
End; End;
///获取docx的类型
///普通段落:0
///图片段落:1
///表格:2
///其他:-1
Function GetDocxPartType(part);
Begin
if not ifObj(part) then return -1;
case part.name_ of
'w:p':
begin
if class(TSXml).GetNode(part.node_, 'w:r/w:drawing') then return 1;
return 0;
end
'w:tbl':
return 2;
else
return -1;
end;
End;
///单元格内的标题是否添加到目录
Function SetCellTableContent(flag);
Begin
hash_["CELLFLAG"] := flag;
End;
Function Set(k, v); Function Set(k, v);
Begin Begin
hash_[k] := v; hash_[k] := v;
+5 -3
View File
@@ -71,12 +71,14 @@ Type TSImage = Class
Begin Begin
des1 := 0xff; des1 := 0xff;
des2 := 0xc0; des2 := 0xc0;
des3 := 0xc2;
flag := 1; flag := 1;
while flag do while flag do
begin begin
stringObj_.Read(byte1, 1); r1 := stringObj_.Read(byte1, 1);
stringObj_.Read(byte2, 1); r2 := stringObj_.Read(byte2, 1);
if byte1 = des1 and byte2 = des2 then flag := 0; if r1 = 0 or r2 = 0 then break;
if byte1 = des1 and (byte2 = des2 or byte2 = des3) then flag := 0;
end end
if flag then return array(0, 0); if flag then return array(0, 0);
stringObj_.Read(tmp, 3); stringObj_.Read(tmp, 3);
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -52,7 +52,7 @@ Type TDocxChart = Class(TSChart)
return true; return true;
End; End;
docx_; [weakref]docx_;
chartId_; chartId_;
rId_; rId_;
xmlObj_; xmlObj_;
+208 -33
View File
@@ -9,6 +9,7 @@ Type TDocxCopy = class
copy_drawing_ := array(); copy_drawing_ := array();
style_copy_obj_ := new TDocxStyleCopy(oldObj.StyleObject(), newObj.StyleObject()); style_copy_obj_ := new TDocxStyleCopy(oldObj.StyleObject(), newObj.StyleObject());
number_copy_obj_ := new TDocxNumberCopy(oldObj, newObj); number_copy_obj_ := new TDocxNumberCopy(oldObj, newObj);
footnote_copy_obj_ := new TDocxFootnoteCopy(oldObj, newObj);
End; End;
Function Init(); Function Init();
@@ -21,7 +22,7 @@ Type TDocxCopy = class
Function Copy(posOpt); Function Copy(posOpt);
Begin Begin
// 复制所有的样式 // 复制所有的样式
style_copy_obj_.CopyStyle(); style_copy_obj_.CopyStyle(number_copy_obj_);
parts := new_docx_obj_.Body().Parts(); parts := new_docx_obj_.Body().Parts();
pos := old_docx_obj_.GetPosNode(posOpt); pos := old_docx_obj_.GetPosNode(posOpt);
@@ -100,6 +101,56 @@ private
end end
End; End;
Function SetRObject(node);
Begin
image_data_node := class(TSXml).GetNode(node, 'v:shape/v:imagedata');
if not ifObj(node) then return;
rid := image_data_node.GetAttribute('r:id');
id := CopyRidContent(rid, 'media/image', 'image');
if id then image_data_node.SetAttribute('r:id', 'rId' $ id);
ole_node := class(TSXml).GetNode(node, 'o:OLEObject');
if not ifObj(node) then return;
rid := ole_node.GetAttribute('r:id');
id := CopyRidContent(rid, 'embeddings/oleObject', 'oleObject');
if id then ole_node.SetAttribute('r:id', 'rId' $ id);
End;
function CopyRidContent(id, tar_prefix, type_postfix);
begin
rels := new_docx_obj_.Zip().Get('word/_rels/document.xml.rels');
target := class(TSXml).FindRelationshipTarget(rels, id);
image_file := new_docx_obj_.Zip().Get('word/' $ target).Data();
// 比较新文件的图片在旧文件中是否存在
zip := old_docx_obj_.Zip();
xml := zip.Get('word/_rels/document.xml.rels');
files := sselect ['FileName'] from zip.Files() where AnsiStartsText('word/' $ tar_prefix, ['FileName']) end;
for i:=0 to length(files)-1 do Begin
if zip.Diff(files[i], image_file) = 0 then Begin
prefix := ReplaceStr(files[i], 'word/', '');
[maxRid, imageFile, rid] := class(TSXml).FindRelationshipRid(xml, prefix);
End;
End;
if rid = 0 then
begin
image_cnt := length(files) + 1;
if ParseRegExpr("\\w+$", target, "", result, Mpos, Mlen) then
begin
postfix := result[0][0];
image_path := tar_prefix $ image_cnt $ '.' $ postfix;
[rid, tar] := class(TSXml).FindRelationshipRid(xml, '');
rid ++;
class(TSXml).AddRelationshipRid(xml, image_path, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' $ type_postfix, 'rId' $ rid);
zip.Add('word/' + image_path, image_file);
contentXml := zip.Get('[Content_Types].xml');
if postfix = 'wmf' then content_type := 'image/x-wmf';
else if postfix = 'bin' then content_type := 'application/vnd.openxmlformats-officedocument.oleObject';
class(TSXml).AddDefaultContentType(contentXml, postfix, content_type);
end
end
return rid;
end;
Function SetPic(node); Function SetPic(node);
Begin Begin
// 获取新文件的图片 // 获取新文件的图片
@@ -110,6 +161,7 @@ private
// 比较新文件的图片在旧文件中是否存在 // 比较新文件的图片在旧文件中是否存在
zip := old_docx_obj_.Zip(); zip := old_docx_obj_.Zip();
xml := zip.Get('word/_rels/document.xml.rels');
files := sselect ['FileName'] from zip.Files() where AnsiStartsText('word/media/image', ['FileName']) end; files := sselect ['FileName'] from zip.Files() where AnsiStartsText('word/media/image', ['FileName']) end;
for i:=0 to length(files)-1 do Begin for i:=0 to length(files)-1 do Begin
if zip.Diff(files[i], image_file) = 0 then Begin if zip.Diff(files[i], image_file) = 0 then Begin
@@ -117,7 +169,6 @@ private
[maxRid, imageFile, rid] := class(TSXml).FindRelationshipRid(xml, prefix); [maxRid, imageFile, rid] := class(TSXml).FindRelationshipRid(xml, prefix);
End; End;
End; End;
xml := zip.Get('word/_rels/document.xml.rels');
if rid = 0 then if rid = 0 then
begin begin
image_cnt := length(files) + 1; image_cnt := length(files) + 1;
@@ -131,9 +182,9 @@ private
zip.Add('word/' + image_path, image_file); zip.Add('word/' + image_path, image_file);
contentXml := zip.Get('[Content_Types].xml'); contentXml := zip.Get('[Content_Types].xml');
class(TSXml).AddDefaultContentType(contentXml, postfix, 'image/' $ postfix); class(TSXml).AddDefaultContentType(contentXml, postfix, 'image/' $ postfix);
node.SetAttribute('r:embed', 'rId' $ rid);
end end
end end
node.SetAttribute('r:embed', 'rId' $ rid);
End; End;
Function SetChart(node); Function SetChart(node);
@@ -198,7 +249,9 @@ private
Function SetDrawingInfo(drawing); Function SetDrawingInfo(drawing);
Begin Begin
graphic_node := class(TSXml).GetNode(drawing.node_,'w:r/w:drawing/wp:inline/a:graphic/a:graphicData'); drawing_node := GetDrawingNode(drawing.node_);
graphic_node := class(TSXml).GetNode(drawing_node,'wp:inline/a:graphic/a:graphicData');
// graphic_node := class(TSXml).GetNode(drawing.node_,'w:r/w:drawing/wp:inline/a:graphic/a:graphicData');
if ifObj(graphic_node) then if ifObj(graphic_node) then
begin begin
node := class(TSXml).GetNode(graphic_node,'pic:pic/pic:blipFill/a:blip'); node := class(TSXml).GetNode(graphic_node,'pic:pic/pic:blipFill/a:blip');
@@ -210,21 +263,67 @@ private
Function SetParagraphInfo(paragraph); Function SetParagraphInfo(paragraph);
Begin Begin
style := class(TSXml).GetNode(paragraph.node_, 'w:pPr/w:pStyle'); CopyStyle(paragraph.node_, 'w:pPr/w:pStyle');
CopyNumber(paragraph.node_, 'w:pPr/w:numPr/w:numId');
SetRunsInfo(paragraph.node_);
DeleteComment(paragraph); // 删除批注
End;
Function SetRunsInfo(node);
Begin
run := node.FirstChildElement('w:r');
while ifObj(run) do
begin
CopyFootnote(run);
CopyStyle(run, 'w:rPr/w:rStyle');
obj_node := class(TSXml).GetNode(run, 'w:object');
if ifObj(obj_node) then
SetRObject(obj_node);
run := run.NextElement();
end
End;
Function CopyStyle(node, path);
Begin
style := class(TSXml).GetNode(node, path);
if ifObj(style) then if ifObj(style) then
begin begin
styleid := style.GetAttribute('w:val'); styleid := style.GetAttribute('w:val');
new_id := style_copy_obj_.GetStyleNewId(styleid); new_id := style_copy_obj_.GetStyleNewId(styleid);
if new_id then style.SetAttribute('w:val', new_id); if new_id then style.SetAttribute('w:val', new_id);
end end
numpr := class(TSXml).GetNode(paragraph.node_, 'w:pPr/w:numPr/w:numId'); End;
Function CopyNumber(node, path);
Begin
numpr := class(TSXml).GetNode(node, path);
if ifObj(numpr) then if ifObj(numpr) then
begin begin
id := numpr.GetAttribute('w:val'); id := numpr.GetAttribute('w:val');
numberid := number_copy_obj_.CopyNumbering(id); numberid := number_copy_obj_.CopyNumbering(id);
numpr.SetAttribute('w:val', id); numpr.SetAttribute('w:val', numberid);
end
End;
Function CopyFootnote(node);
Begin
footnote := node.FirstChildElement('w:footnoteReference');
if not ifObj(footnote) then return;
id := footnote.GetAttribute('w:id');
if id then
begin
obj := footnote_copy_obj_.CopyFootnote(id);
footnote.SetAttribute('w:id', obj.Id);
parts := obj.Parts();
for i:=0 to length(parts)-1 do
begin
case GetPartType(parts[i]) of
0: SetParagraphInfo(parts[i]);
1: SetDrawingInfo(parts[i]);
2: SetTableInfo(parts[i]);
end;
end
end end
DeleteComment(paragraph); // 删除批注
End; End;
Function SetTableInfo(table); Function SetTableInfo(table);
@@ -244,27 +343,33 @@ private
begin begin
cell := table.Cell(r, c); cell := table.Cell(r, c);
if not cell then continue; if not cell then continue;
node := cell.node_; node := cell.node_.FirstChildElement();
if (tbl := node.FirstChildElement('w:tbl')) then while ifObj(node) do
begin begin
obj := TOfficeObj('TTable'); name := node.GetName();
obj.Init(tbl); if name = 'w:tbl' then
SetTableInfo(obj);
end
else if (p := node.FirstChildElement('w:p')) then
begin
draw := class(TSXml).GetNode(p, 'w:r/w:drawing');
if ifObj(draw) then
begin begin
obj := TOfficeObj('TPicture'); obj := TOfficeObj('TTable');
obj.Init(p); obj.Init(node);
SetDrawingInfo(obj); SetTableInfo(obj);
end end
else begin else if name = "w:p" then
obj := TOfficeObj('TParagraph'); begin
obj.Init(p); // draw := class(TSXml).GetNode(node, 'w:r/w:drawing');
SetParagraphInfo(obj); draw := GetDrawingNode(node);
if ifObj(draw) then
begin
obj := TOfficeObj('TPicture');
obj.Init(node);
SetDrawingInfo(obj);
end
else begin
obj := TOfficeObj('TParagraph');
obj.Init(node);
SetParagraphInfo(obj);
end
end end
node := node.NextElement();
end end
end end
end end
@@ -280,6 +385,7 @@ private
case name of case name of
'w:p': 'w:p':
begin begin
if GetDrawingNode(part.node_) then return 1;
if class(TSXml).GetNode(part.node_, 'w:r/w:drawing') then return 1; if class(TSXml).GetNode(part.node_, 'w:r/w:drawing') then return 1;
return 0; return 0;
end end
@@ -290,11 +396,32 @@ private
end end
End; End;
function GetDrawingNode(node);
begin
r_node := node.FirstChild('w:r');
while ifObj(r_node) do
begin
sub_node := r_node.FirstChild();
sub_node_name := sub_node.GetName();
if sub_node_name = 'w:rPr' then
begin
sub_node := sub_node.NextElement();
sub_node_name := sub_node.GetName();
end
if sub_node_name = 'w:drawing' then return sub_node;
if sub_node_name = 'w:t' and sub_node.GetAttribute('xml:space') = 'preserve' then
r_node := r_node.NextElement();
else break;
end
return nil;
end;
private private
old_docx_obj_; old_docx_obj_;
new_docx_obj_; new_docx_obj_;
style_copy_obj_; style_copy_obj_;
number_copy_obj_; number_copy_obj_;
footnote_copy_obj_;
copy_table_; copy_table_;
copy_paragraph_; copy_paragraph_;
@@ -326,11 +453,12 @@ Type TDocxStyleCopy = class
end end
End; End;
Function CopyStyle(); Function CopyStyle(numberobj);
Begin Begin
for id, obj in id_map_ do for id, obj in id_map_ do
begin begin
SetBasedOn(obj); SetBasedOn(obj);
SetNumId(obj, numberobj);
SetLink(obj); SetLink(obj);
old_style_obj_.CopyStyle(obj); old_style_obj_.CopyStyle(obj);
end; end;
@@ -382,21 +510,31 @@ private
end end
End; End;
Function SetNumId(obj, numberobj);
Begin
if not ifObj(numberobj) then return;
numPr := class(TSXml).GetNode(obj.node_, 'w:pPr/w:numPr/w:numId');
if ifObj(numPr) then
begin
id := numpr.GetAttribute('w:val');
numberid := numberobj.CopyNumbering(id);
numpr.SetAttribute('w:val', numberid);
end
End;
Function GetNewName(name); Function GetNewName(name);
Begin Begin
new_name := name; new_name := name;
count := 0; while ifObj(old_style_obj_.GetStyle(class(TSXml).Utf8ToCurCodePage(new_name))) or style_name_map2_[new_name] do
while ifObj(old_style_obj_.GetStyle(new_name)) or style_name_map2_[new_name] do new_name := new_name $ crc32(inttostr(random(2000000)));
new_name := new_name $ count++;
return new_name; return new_name;
End; End;
Function GetNewId(id); Function GetNewId(id);
Begin Begin
new_id := id; new_id := id;
count := 0;
while ifObj(old_style_obj_.GetStyleById(new_id)) or style_id_map2_[new_id] do while ifObj(old_style_obj_.GetStyleById(new_id)) or style_id_map2_[new_id] do
new_id := new_id $ count++; new_id := new_id $ crc32(inttostr(random(2000000)));
return new_id; return new_id;
End; End;
@@ -437,9 +575,9 @@ Type TDocxNumberCopy = class
begin begin
number_obj := old_number_obj_.CopyNumber(obj); number_obj := old_number_obj_.CopyNumber(obj);
id_map_[number] := number_obj; id_map_[number] := number_obj;
return number_obj;
end end
end; return id_map_[number];
end
End; End;
private private
@@ -448,3 +586,40 @@ private
id_map_; // [id: styleobj] id_map_; // [id: styleobj]
End; End;
Type TDocxFootnoteCopy = class
Function Create(oldObj, newObj);
Begin
footnotexml := newObj.Zip().Get('word/footnotes.xml');
if ifObj(footnotexml) then
begin
old_footnote_obj_ := oldObj.FootNotesObject();
new_footnote_obj_ := newObj.FootNotesObject();
end
else begin
old_footnote_obj_ := nil;
new_footnote_obj_ := nil;
end
id_map_ := array();
End;
Function CopyFootnote(id);
Begin
if ifObj(old_footnote_obj_) and ifObj(new_footnote_obj_) then
begin
if (obj := new_footnote_obj_.GetFootnote(id)) and not id_map_[id] then
begin
footnote_obj := old_footnote_obj_.CopyFootnote(obj);
id_map_[id] := footnote_obj;
end
return id_map_[id];
end
End;
private
[weakref]old_footnote_obj_;
new_footnote_obj_;
id_map_; // [id: footnote]
End;
+2 -1
View File
@@ -141,6 +141,7 @@ Type TDocxStyles = Class
Begin Begin
if ifObj(newstyle) and ifObj(newstyle.node_) then Begin if ifObj(newstyle) and ifObj(newstyle.node_) then Begin
node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(newstyle.node_.Marshal()[0]); node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(newstyle.node_.Marshal()[0]);
node.DeleteAttribute('w:default');
obj := TOfficeObj('TDocxStyle'); obj := TOfficeObj('TDocxStyle');
obj.StyleId := node.GetAttribute('w:styleId'); obj.StyleId := node.GetAttribute('w:styleId');
obj.Name := node.FirstChildElement('w:name').GetAttribute('w:val'); obj.Name := node.FirstChildElement('w:name').GetAttribute('w:val');
@@ -198,7 +199,7 @@ Type TDocxStyles = Class
defaultPpr_; defaultPpr_;
defaultRpr_; defaultRpr_;
private private
docx_; [weakref]docx_;
stylesXml_; stylesXml_;
idMap_; idMap_;
nameMap_; nameMap_;
+1 -1
View File
@@ -228,7 +228,7 @@ Type TNumbering = Class
class(TSXml).UpdateNode(o.node_, arr['attributes'], arr['children']); class(TSXml).UpdateNode(o.node_, arr['attributes'], arr['children']);
End; End;
private private
docx_; [weakref]docx_;
numberingXml_; numberingXml_;
maxAbstractNumId_:integer; maxAbstractNumId_:integer;
maxNumId_:integer; maxNumId_:integer;
+39 -9
View File
@@ -94,6 +94,16 @@ Type TTableContent = class
_AddTableContent(posOpt, UpperHeadingLevel, LowerHeadingLevel); _AddTableContent(posOpt, UpperHeadingLevel, LowerHeadingLevel);
End; End;
///添加目录条目
///UpperHeadingLevel:标题最高级别
///LowerHeadingLevel:标题最低级别
/// 使用 UpperHeadingLevel 属性可设置起始标题级别(最高)。例如,若要设置 TOC 域语法 {TOC \o "1-3"},可将 LowerHeadingLevel 属性设为 3,并将 UpperHeadingLevel 属性设为 1。
Function CustomAdd(posOpt, UpperHeadingLevel, LowerHeadingLevel);
Begin
//自定义页码计算与word、wps有差异,不推荐使用
_AddTableContent(posOpt, UpperHeadingLevel, LowerHeadingLevel);
End;
Function _AddDefaultTableContent(UpperHeadingLevel, LowerHeadingLevel); Function _AddDefaultTableContent(UpperHeadingLevel, LowerHeadingLevel);
Begin Begin
p := _AddItem(UpperHeadingLevel, LowerHeadingLevel, UpperHeadingLevel - 1, true); p := _AddItem(UpperHeadingLevel, LowerHeadingLevel, UpperHeadingLevel - 1, true);
@@ -118,13 +128,13 @@ Type TTableContent = class
tab := TOfficeObj('TTabStop'); tab := TOfficeObj('TTabStop');
tab.Val := 'right'; tab.Val := 'right';
tab.leader := 'dot'; tab.leader := 'dot';
tab.Position := 8640; tab.Position := TOfficeApi().Get("TTableContent-tab-position") ?: 8306;
p.Format.Tabs.Add(0, tab); p.Format.Tabs.Add(0, tab);
if first then Begin if first then Begin
//fldCharType //fldCharType
r1 := p.AddRun(); r1 := p.AddRun();
r1.fldCharType := 'begin'; r1.fldCharType := 'begin';
r1.Dirty := 'true'; r1.Dirty := 0;
//instrText //instrText
r2 := p.AddRun(); r2 := p.AddRun();
@@ -142,7 +152,7 @@ Type TTableContent = class
Begin Begin
///获取标题列表 array((("Level":level,"Paragraph":"object","Text":title,"numId":,"ilvl":,"numArr":)); ///获取标题列表 array((("Level":level,"Paragraph":"object","Text":title,"numId":,"ilvl":,"numArr":));
numMap := array(); numMap := array();
r := docx_.Document().Body().GetHeadingListImpl(docx_, posOpt, UpperHeadingLevel, LowerHeadingLevel, numMap, true); r := docx_.Document().Body().GetHeadingListImpl(docx_, nil, UpperHeadingLevel, LowerHeadingLevel, numMap);
for i:=0 to length(r)-1 do Begin for i:=0 to length(r)-1 do Begin
p := _AddItem(UpperHeadingLevel, LowerHeadingLevel, r[i]['Level'], i = 0 ? true: false); p := _AddItem(UpperHeadingLevel, LowerHeadingLevel, r[i]['Level'], i = 0 ? true: false);
//fldCharType //fldCharType
@@ -160,9 +170,9 @@ Type TTableContent = class
if ifObj(style) then if ifObj(style) then
numStr := style.GetText(r[i]['ilvl'], r[i]['numArr']); numStr := style.GetText(r[i]['ilvl'], r[i]['numArr']);
End End
if numStr <> '' then run_t := numStr + ' ' + r[i]['Text']; run_t := class(TSXml).CurCodePageToUtf8(r[i]['Text']);
else run_t := r[i]['Text']; if numStr <> '' then run_t := numStr + ' ' + run_t;
r1.SetText(run_t); r1.SetText(run_t, 1);
r2 := h.AddRun(); r2 := h.AddRun();
r2.rPr.noProof := true; r2.rPr.noProof := true;
@@ -203,7 +213,6 @@ Type TTableContent = class
r8.fldCharType := 'end'; r8.fldCharType := 'end';
_AddStdContent(p); _AddStdContent(p);
End; End;
p2 := TOfficeObj('TParagraph'); p2 := TOfficeObj('TParagraph');
@@ -221,6 +230,26 @@ Type TTableContent = class
Begin Begin
End; End;
Function Paragraphs();
Begin
node := class(TSXml).GetNode(docx_.Document().Body().Node(), 'w:sdt/w:sdtContent');
r := array();
if ifObj(node) then
begin
twbody := TOfficeObj('TwBody');
twbody.Create(nil, 'w:sdtContent');
twbody.InitRootNode(node);
twbody.InitNode(node);
parts := twbody.Paragraphs();
for i:=0 to length(parts)-1 do
begin
r[i] := TOfficeObj('TParagraph');
r[i].Init(parts[i].node_);
end
end
return r;
End;
Function Marshal(); Function Marshal();
Begin Begin
return impl_.Marshal(); return impl_.Marshal();
@@ -265,7 +294,7 @@ Type TTableContent = class
if ifObj(node) then if ifObj(node) then
return node.GetAttribute('w:name'); return node.GetAttribute('w:name');
bookMarkID := docx_.Document().GetBookMarkID(); bookMarkID := docx_.Document().GetBookMarkID();
return p.AddBookMark(); return p.AddBookMark(bookMarkID);
End; End;
Function _CheckNodes(name); Function _CheckNodes(name);
@@ -295,7 +324,8 @@ Type TTableContent = class
End; End;
End; End;
docx_; [weakref]docx_;
node_; node_;
impl_; impl_;
End; End;
+7 -1
View File
@@ -10,6 +10,7 @@ Type docxDocument = Class
bodyNode_ := root_.FirstChildElement('w:body'); bodyNode_ := root_.FirstChildElement('w:body');
body_ := TOfficeObj('TwBody'); body_ := TOfficeObj('TwBody');
body_.InitNode(bodyNode_); body_.InitNode(bodyNode_);
body_.InitRootNode(bodyNode_);
body_.zipfile_ := z; body_.zipfile_ := z;
body_.document_ := self; body_.document_ := self;
bookmarkid_ := -1; bookmarkid_ := -1;
@@ -20,6 +21,11 @@ Type docxDocument = Class
return body_; return body_;
End; End;
Function AddNameSpace(prefix, uri);
Begin
root_.SetAttribute('xmlns:' + prefix, uri);
End;
Function GetBookMarkID(); Function GetBookMarkID();
Begin Begin
if bookmarkid_ < 0 then Begin if bookmarkid_ < 0 then Begin
@@ -29,7 +35,7 @@ Type docxDocument = Class
markStart := p.FirstChildElement('w:bookmarkStart'); markStart := p.FirstChildElement('w:bookmarkStart');
if ifObj(markStart) then Begin if ifObj(markStart) then Begin
id := markStart.GetAttribute('w:id'); id := markStart.GetAttribute('w:id');
if ifstring(id) then Begin if ifstring(id) and id <> '' then Begin
iVal := strtoint(id); iVal := strtoint(id);
if bookmarkid_ <= iVal then if bookmarkid_ <= iVal then
bookmarkid_ := iVal + 1; bookmarkid_ := iVal + 1;
+1 -1
View File
@@ -65,7 +65,7 @@ Type xlsxChart = Class(TSChart)
node := drawingXmlObj_.FirstChild('xdr:wsDr').InsertEndChild(o.Marshal()); node := drawingXmlObj_.FirstChild('xdr:wsDr').InsertEndChild(o.Marshal());
End; End;
private private
excel_; [weakref]excel_;
drawingRID_:integer; drawingRID_:integer;
chartId_; chartId_;
chartRid_; chartRid_;
+6 -2
View File
@@ -148,7 +148,11 @@ xmlns:v="urn:schemas-microsoft-com:vml">
comment += r_node.FirstChildElement('t').GetText(); comment += r_node.FirstChildElement('t').GetText();
r_node := r_node.NextElement(); r_node := r_node.NextElement();
end end
if length(comment) > 1 then comment := comment[2:]; if length(comment) > 1 then
begin
if comment[1] = "\n" then comment := comment[2:];
else if comment[1:2] = "\r\n" then comment := comment[3:];
end
return array(author, comment); return array(author, comment);
End; End;
@@ -180,6 +184,7 @@ private
End; End;
End; End;
[weakref]excel_;//TSXlsxFile对象
authors_; authors_;
commentId_; commentId_;
commentFileName_:string;//'../comments/comment1.xml' commentFileName_:string;//'../comments/comment1.xml'
@@ -187,7 +192,6 @@ private
rId_:string; rId_:string;
sheetName_:string;//sheet名称 sheetName_:string;//sheet名称
sheetFileName_;//xl/worksheets/sheetN.xml sheetFileName_;//xl/worksheets/sheetN.xml
excel_;//TSExcelFile对象
commentXmlFile_;//XmlFile对象 commentXmlFile_;//XmlFile对象
commentObjs_; commentObjs_;
End; End;
+1 -1
View File
@@ -45,5 +45,5 @@ Type xlsxDocProps = Class
End; End;
private private
excel_; //TSExcelFile对象 [weakref]excel_; //TSExcelFile对象
End; End;
@@ -33,6 +33,6 @@ Type xlsxHeaderFooter = Class
private private
sheet_; //XmlSheet对象 sheet_; //XmlSheet对象
file_; //TSExcelFile对象 [weakref]file_; //TSExcelFile对象
xmlFile_; //sheet对应的xml对象 xmlFile_; //sheet对应的xml对象
End; End;
+1 -1
View File
@@ -92,7 +92,7 @@ Type xlsxHyperLink = Class
End; End;
private private
file_; //TSExcelFile对象 [weakref]file_; //TSExcelFile对象
xmlFile_;//XmlFile对象 xmlFile_;//XmlFile对象
sheetName_; sheetName_;
+1 -1
View File
@@ -169,6 +169,6 @@ private
private private
sheetName_:string; //sheet名称 sheetName_:string; //sheet名称
excel_;//TSExcelFile对象 [weakref]excel_;//TSExcelFile对象
zipfile_; zipfile_;
End; End;
@@ -38,7 +38,7 @@ Type xlsxPageLayout = Class
End; End;
private private
file_; //TSExcelFile对象 [weakref]file_; //TSExcelFile对象
sheet_;//XmlSheet对象 sheet_;//XmlSheet对象
xmlFile_; //sheet对应的xml对象 xmlFile_; //sheet对应的xml对象
End; End;
+1 -1
View File
@@ -113,7 +113,7 @@ private
private private
sheetName_:string; //sheet名称 sheetName_:string; //sheet名称
excel_;//TSExcelFile对象 [weakref]excel_;//TSExcelFile对象
zipfile_; zipfile_;
drawingXmlObj_; drawingXmlObj_;
End; End;
+1 -1
View File
@@ -95,7 +95,7 @@ Type xlsxSheetView = Class
End; End;
private private
file_; //TSExcelFile对象 [weakref]file_; //TSExcelFile对象
sheet_;//XmlSheet对象 sheet_;//XmlSheet对象
xmlFile_; //sheet对应的xml对象 xmlFile_; //sheet对应的xml对象
End; End;
+126 -22
View File
@@ -1,15 +1,29 @@
Type xlsxStyles = Class Type xlsxStyles = Class
Function Create(sheetobj, file); Function Create(file);
Begin Begin
sheet_ := sheetobj;
file_ := file; file_ := file;
styleXmlFile_ := file_.WorkBook().GetXmlFileObj('xl/styles.xml'); style_xml_file_ := file_.WorkBook().GetXmlFileObj('xl/styles.xml');
style_ := array();
Init();
End 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; Function GetStyleId(style);overload;
Begin Begin
node := styleXmlFile_.FirstChildElement('styleSheet'); node := style_xml_file_.FirstChildElement('styleSheet');
font_id := insertNode(node, 'fonts', style.Font); font_id := insertNode(node, 'fonts', style.Font);
border_id := insertNode(node, 'borders', style.Border); border_id := insertNode(node, 'borders', style.Border);
fill_id := insertNode(node, 'fills', style.Fill); fill_id := insertNode(node, 'fills', style.Fill);
@@ -40,15 +54,16 @@ Type xlsxStyles = Class
node := node.FirstChildElement('cellXfs'); node := node.FirstChildElement('cellXfs');
count := node.GetAttribute('count'); count := node.GetAttribute('count');
node.InsertEndChild(xf.Marshal());
node.SetAttribute('count', strtoint(count) + 1); node.SetAttribute('count', strtoint(count) + 1);
xf_node := node.InsertEndChild(xf.Marshal());
style_[count] := xf_node;
return count; return count;
End; End;
Function GetStyleId(newStyle, oldStyleId);overload; Function GetStyleId(newStyle, oldStyleId);overload;
Begin Begin
if oldStyleId = '' then return nil; if oldStyleId = '' then return nil;
style_node := styleXmlFile_.FirstChildElement('styleSheet'); style_node := style_xml_file_.FirstChildElement('styleSheet');
cellXfs_node := style_node.FirstChildElement('cellXfs'); cellXfs_node := style_node.FirstChildElement('cellXfs');
count := strtoint(cellXfs_node.GetAttribute('count')); count := strtoint(cellXfs_node.GetAttribute('count'));
Id := strtoint(oldStyleId); Id := strtoint(oldStyleId);
@@ -89,19 +104,14 @@ Type xlsxStyles = Class
xf_node.SetAttribute('applyProtection', 1); xf_node.SetAttribute('applyProtection', 1);
end end
style_[inttostr(count)] := xf_node;
return inttostr(count); return inttostr(count);
End; End;
Function GetStyle(styleId); Function GetStyle(styleId);
Begin Begin
if styleId = '' then return nil; xf := style_[styleId];
style_node := styleXmlFile_.FirstChildElement('styleSheet'); if not ifObj(xf) then return nil;
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);
attrs := xf.Attributes(); attrs := xf.Attributes();
numfmt_id := trystrtoint(attrs['numFmtId'], r) ? r : 0; numfmt_id := trystrtoint(attrs['numFmtId'], r) ? r : 0;
font_id := trystrtoint(attrs['fontId'], r) ? r : 0; font_id := trystrtoint(attrs['fontId'], r) ? r : 0;
@@ -110,6 +120,7 @@ Type xlsxStyles = Class
alignment := xf.FirstChildElement('alignment'); alignment := xf.FirstChildElement('alignment');
protection := xf.FirstChildElement('protection'); protection := xf.FirstChildElement('protection');
style_node := style_xml_file_.FirstChildElement('styleSheet');
style := TOfficeObj('TStyle'); style := TOfficeObj('TStyle');
numFmts_node := style_node.FirstChildElement('numFmts'); numFmts_node := style_node.FirstChildElement('numFmts');
fonts_node := style_node.FirstChildElement('fonts'); fonts_node := style_node.FirstChildElement('fonts');
@@ -127,12 +138,51 @@ Type xlsxStyles = Class
return style; return style;
End; End;
class Function NewObject(sheetname, file); Function GetNumFmtId(styleId);
Begin Begin
o := file.WorkBook().GetSheetObj(sheetname); node := style_[styleId];
if not ifObj(o) then return 0; if ifnil(node) then return '0';
styles := new xlsxStyles(o, file); numfmt := node.GetAttribute("numFmtId");
return styles; 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) or trystrtotime(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', 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 (pos("-", value) or pos("/", value)) and (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; End;
private private
@@ -286,7 +336,61 @@ private
End End
private private
sheet_; //XmlSheet对象 [weakref]file_; //TSXlsxFile对象
file_; //TSExcelFile对象 style_xml_file_;
styleXmlFile_; //xmlFile对象 style_; // 缓存style
End; End;
// 参考:https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.numberingformat?view=openxml-3.0.1
// 0 General
// 1 0
// 2 0.00
// 3 #,##0
// 4 #,##0.00
// 5 整数,货币符号旁边($#,##0_);($#,##0)
// 6 带两位小数的货币符号($#,##0.00_);($#,##0.00)
// 7 整数,带括号表示负数($#,##0_);Red
// 8 带两位小数的货币符号和红色负数($#,##0.00_);Red
// 9 0%
// 10 0.00%
// 11 0.00E+00
// 12 # ?/?
// 13 # ??/??
// 14 mm-dd-yy
// 15 d-mmm-yy
// 16 d-mmm
// 17 mmm-yy
// 18 h:mm AM/PM
// 19 h:mm:ss AM/PM
// 20 h:mm
// 21 h:mm:ss
// 22 m/d/yy h:mm
// 27 [$-404]e/m/d yyyy"年"m"月"
// 28 [$-404]e"年"m"月"d"日" m"月"d"日"
// 29 [$-404]e"年"m"月"d"日" m"月"d"日"
// 30 m/d/yy m-d-yy
// 31 yyyy"年"m"月"d"日" yyyy"年"m"月"d"日"
// 32 hh"時"mm"分" h"时"mm"分"
// 33 hh"時"mm"分"ss"秒" h"时"mm"分"ss"秒"
// 34 上午/下午hh"時"mm"分" 上午/下午h"时"mm"分"
// 35 上午/下午hh"時"mm"分"ss"秒" 上午/下午h"时"mm"分"ss"秒"
// 36 [$-404]e/m/d yyyy"年"m"月"
// 37 #,##0 ;(#,##0)
// 38 #,##0 ;[Red](#,##0)
// 39 #,##0.00;(#,##0.00)
// 40 #,##0.00;[Red](#,##0.00)
// 45 mm:ss
// 46 [h]:mm:ss
// 47 mmss.0
// 48 ##0.0E+0
// 49 @(文本)
// 50 [$-404]e/m/d yyyy"年"m"月"
// 51 [$-404]e"年"m"月"d"日" m"月"d"日"
// 52 上午/下午hh"時"mm"分" yyyy"年"m"月"
// 53 上午/下午hh"時"mm"分"ss"秒" m"月"d"日"
// 54 [$-404]e"年"m"月"d"日" m"月"d"日"
// 55 上午/下午hh"時"mm"分" 上午/下午h"时"mm"分"
// 56 上午/下午hh"時"mm"分"ss"秒" 上午/下午h"时"mm"分"ss"秒"
// 57 [$-404]e/m/d yyyy"年"m"月"
// 58 [$-404]e"年"m"月"d"日" m"月"d"日"
+1 -1
View File
@@ -126,7 +126,7 @@ private
private private
sheetName_:string; //sheet名称 sheetName_:string; //sheet名称
excel_;//TSExcelFile对象 [weakref]excel_;//TSExcelFile对象
zipfile_; zipfile_;
tableXmlFile_; tableXmlFile_;
End; End;
+229 -188
View File
@@ -40,7 +40,7 @@ Type xlsxWorkBook = Class
//workbook.Print(); //workbook.Print();
//workbook.Dump(); //workbook.Dump();
//echo tostn(workbook.dom()); //echo tostn(workbook.dom());
node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').FirstChildElement(); node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').FirstChildElement('sheet');
while ifObj(node) do Begin while ifObj(node) do Begin
name := node.GetAttribute("name"); name := node.GetAttribute("name");
sheetNames_[sheetsCount_]['name'] := name; sheetNames_[sheetsCount_]['name'] := name;
@@ -50,7 +50,7 @@ Type xlsxWorkBook = Class
sheetNames_[sheetsCount_]['file'] := 'xl/' + rids[ rid ]; sheetNames_[sheetsCount_]['file'] := 'xl/' + rids[ rid ];
sheetIndexMap_[ LowerCase(name) ] := sheetsCount_; sheetIndexMap_[ LowerCase(name) ] := sheetsCount_;
sheetsCount_ ++; sheetsCount_ ++;
node := node.NextElement(); node := node.NextElement('sheet');
End; End;
files := zipfile_.Files(); files := zipfile_.Files();
@@ -108,7 +108,39 @@ Type xlsxWorkBook = Class
Function SetCellValue(sheet, axis, val, opt); Function SetCellValue(sheet, axis, val, opt);
Begin Begin
o := GetSheetObj(sheet); o := GetSheetObj(sheet);
if ifObj(o) then return o.SetCellValue(axis, val, opt); if ifObj(o) then
ret := o.SetCellValue(axis, val, opt);
return ret;
End;
Function SetCellStyleOpt(sheet, axis, opt);
Begin
o := GetSheetObj(sheet);
if ifObj(o) then
begin
if ifnil(opt['s']) and not o.CellIsExists(axis) then
begin
[err, col, row] := CellNameToCoordinates(axis);
xml := GetSheetXmlFile(sheet);
cols_node := xml.FirstChildElement('worksheet').FirstChildElement('cols');
if ifObj(cols_node) then
begin
col_node := cols_node.FirstChildElement();
while ifObj(col_node) do
begin
min := strtoint(col_node.GetAttribute('min'));
max := strtoint(col_node.GetAttribute('max'));
style := col_node.GetAttribute('style');
if col >= min and col <= max and style <> '' then
begin
opt['s'] := style;
break;
end
col_node := col_node.NextElement();
end
end
end
end
End; End;
Function GetCellRichText(sheet, axis); Function GetCellRichText(sheet, axis);
@@ -146,7 +178,7 @@ Type xlsxWorkBook = Class
data := o.Import(topLeft, bottomRight, includeHeader, includeIndex, forceSingle); data := o.Import(topLeft, bottomRight, includeHeader, includeIndex, forceSingle);
if not TOfficeApi().IsUtf8() then if not TOfficeApi().IsUtf8() then
begin begin
fields := fieldnames(data); fields := mcols(data, 1);
if ifarray(fields) and length(fields) then if ifarray(fields) and length(fields) then
begin begin
map := array(); map := array();
@@ -166,62 +198,142 @@ Type xlsxWorkBook = Class
Begin Begin
lname := LowerCase(sheet); lname := LowerCase(sheet);
if ifint(sheetIndexMap_[ lname ]) then return 'The sheet already exists.'; if ifint(sheetIndexMap_[ lname ]) then return 'The sheet already exists.';
rid := getWorkbookRelsRid();
fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml';
sheetId := addSheetN(fname);
rid := setWorkbookRels();
setWorkbookSheet(sheet, sheetId, rid);
setDocPropsApp(sheet);
setContentTypes(fname);
sheetNames_[sheetsCount_]['name'] := sheet;
sheetNames_[sheetsCount_]['sheetId'] := sheetId;
sheetNames_[sheetsCount_]['rid'] := rid;
sheetNames_[sheetsCount_]['file'] := fname;
sheetIndexMap_[ lname ] := sheetsCount_;
sheetsCount_ ++;
SetDefaultSheet(sheet);
End;
Function addSheetN(fname);
Begin
//添加文件xl/worksheets/sheetN.xml //添加文件xl/worksheets/sheetN.xml
sheetId := vselect maxof(['sheetId']) from sheetNames_ end; sheetId := vselect maxof(['sheetId']) from sheetNames_ end;
sheetId := integer(sheetId) + 1; sheetId := integer(sheetId) + 1;
fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml';
zipfile_.Add(fname, class(TSXml).XmlHeader() + class(TSXml).GetTemplate('sheet1')); zipfile_.Add(fname, class(TSXml).XmlHeader() + class(TSXml).GetTemplate('sheet1'));
return sheetId;
End;
Function setWorkbookRels();
Begin
rid := getWorkbookRelsRid();
//设置 workbook.xml.rels //设置 workbook.xml.rels
workbook_rels := GetXmlFileObj('xl/_rels/workbook.xml.rels'); workbook_rels := GetXmlFileObj('xl/_rels/workbook.xml.rels');
rels := workbook_rels.FirstChildElement('Relationships').InsertEndChild('element', 'Relationship'); rels := workbook_rels.FirstChildElement('Relationships').InsertEndChild('element', 'Relationship');
rels.SetAttribute('Target', getTarget( sheetsCount_ + 1)); rels.SetAttribute('Target', getTarget( sheetsCount_ + 1));
rels.SetAttribute('Type', class(TSXml).GetTemplate('RelationshipWorkSheet')); rels.SetAttribute('Type', class(TSXml).GetTemplate('RelationshipWorkSheet'));
rels.SetAttribute('Id', rid); rels.SetAttribute('Id', rid);
//workbook_rels.Print; return rid;
End;
Function setWorkbookSheet(sheetName, sheetId, rid);
Begin
//设置 xl/workbook.xml //设置 xl/workbook.xml
workbook := GetXmlFileObj('xl/workbook.xml'); workbook := GetXmlFileObj('xl/workbook.xml');
node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').InsertEndChild('element','sheet'); node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').InsertEndChild('element','sheet');
node.SetAttribute('name', sheet); node.SetAttribute('name', sheetName);
node.SetAttribute('sheetId', sheetId); node.SetAttribute('sheetId', sheetId);
node.SetAttribute('r:id', rid); node.SetAttribute('r:id', rid);
//workbook.Print(); End;
Function setDocPropsApp(sheet);
Begin
//设置docProps/app.xml //设置docProps/app.xml
app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app')); app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app'));
//app.Print(); properties_node := app.FirstChildElement('Properties');
node := app.FirstChildElement('Properties').FirstChildElement('TitlesOfParts'); // HeadingPairs
if not ifObj(node) then Begin variant_node := class(TSXml).GetNode(properties_node, 'HeadingPairs/vt:vector/vt:variant');
node := app.FirstChildElement('Properties').InsertEndChild('element','TitlesOfParts'); while ifObj(variant_node) do
End; begin
vector := node.FirstChildElement('vt:vector'); vt_node := variant_node.FirstChildElement('vt:i4');
if not ifObj(vector) then Begin if ifObj(vt_node) then
vector := node.InsertEndChild('element', 'vt:vector'); begin
vector.SetAttribute('baseType', 'lpstr'); vt_node.SetValue(length(sheetNames_) + 1);
vector.SetAttribute('size', length(sheetNames_) + 1); break;
for i:=0 to length(sheetNames_)-1 do Begin end
vector.InsertEndChild('element', 'vt:lpstr', sheetNames_[i]['name']); variant_node := variant_node.NextElement();
End; end
End
else
vector.SetAttribute('size', length(sheetNames_) + 1);
vector.InsertEndChild('element', 'vt:lpstr', sheet);
//app.Print();
// TitlesOfParts
vector := class(TSXml).GetNode(properties_node, 'TitlesOfParts/vt:vector');
vector.SetAttribute('size', length(sheetNames_) + 1);
vector.InsertEndChild('element', 'vt:lpstr', sheet);
End;
Function setContentTypes(fname);
Begin
//设置[Content_Types].xml //设置[Content_Types].xml
content_xml := GetXmlFileObj(class(TSXml).GetFileName('Content_Types')); content_xml := GetXmlFileObj(class(TSXml).GetFileName('Content_Types'));
class(TSXml).AddOverrideContentType(content_xml, '/' + fname, class(TSXml).GetTemplate('sheetContentType')); class(TSXml).AddOverrideContentType(content_xml, '/' + fname, class(TSXml).GetTemplate('sheetContentType'));
End;
sheetNames_[sheetsCount_]['name'] := sheet; Function insertWorkbookSheet(targetSheetName, newSheetName, sheetId, rId, direction);
sheetNames_[sheetsCount_]['sheetId'] := sheetId; Begin
sheetNames_[sheetsCount_]['rid'] := rid; workbook := GetXmlFileObj('xl/workbook.xml');
sheetNames_[sheetsCount_]['file'] := fname; node := class(TSXml).GetNode(workbook, 'workbook/sheets');
sheetIndexMap_[ LowerCase(sheet) ] := sheetsCount_; sheet_node := node.FirstChildElement('sheet');
sheetsCount_ ++; while ifObj(sheet_node) do
SetDefaultSheet(sheet); begin
if sheet_node.GetAttribute('name') = targetSheetName then
begin
if direction = "after" then
sheet_node := node.InsertAfterChild(sheet_node, 'element', 'sheet');
else
sheet_node := node.InsertBeforeChild(sheet_node, 'element', 'sheet');
sheet_node.SetAttribute('name', newSheetName);
sheet_node.SetAttribute('sheetId', sheetId);
sheet_node.SetAttribute('r:id', rid);
break;
end
sheet_node := sheet_node.NextElement();
end
End;
Function insertDocPropsApp(targetSheetName, newSheetName, direction);
Begin
//设置docProps/app.xml
app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app'));
properties_node := app.FirstChildElement('Properties');
// HeadingPairs
variant_node := class(TSXml).GetNode(properties_node, 'HeadingPairs/vt:vector/vt:variant');
while ifObj(variant_node) do
begin
vt_node := variant_node.FirstChildElement('vt:i4');
if ifObj(vt_node) then
begin
vt_node.SetValue(length(sheetNames_) + 1);
break;
end
variant_node := variant_node.NextElement();
end
// TitlesOfParts
vector := class(TSXml).GetNode(properties_node, 'TitlesOfParts/vt:vector');
vector.SetAttribute('size', length(sheetNames_) + 1);
lpstr := vector.FirstChildElement('vt:lpstr');
while ifObj(lpstr) do
begin
if LowerCase(lpstr.GetText()) = LowerCase(targetSheetName) then
begin
if direction = 'after' then
lpstr := vector.InsertAfterChild(lpstr, 'element', 'vt:lpstr');
else
lpstr := vector.InsertBeforeChild(lpstr, 'element', 'vt:lpstr');
lpstr.SetValue(newSheetName);
break;
end
lpstr := lpstr.NextElement();
end
End; End;
Function NewSheet(sourceSheet, destSheet);overload; Function NewSheet(sourceSheet, destSheet);overload;
@@ -231,60 +343,12 @@ Type xlsxWorkBook = Class
sname := LowerCase(sourceSheet); sname := LowerCase(sourceSheet);
if not ifint(sheetIndexMap_[ sname ]) then return 'sourceSheet does not exists'; if not ifint(sheetIndexMap_[ sname ]) then return 'sourceSheet does not exists';
//添加文件xl/worksheets/sheetN.xml
sheetId := vselect maxof(['sheetId']) from sheetNames_ end;
sheetId := integer(sheetId) + 1;
fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml'; fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml';
zipfile_.Add(fname, class(TSXml).XmlHeader() + class(TSXml).GetTemplate('sheet1')); sheetId := addSheetN(fname);
rid := setWorkbookRels();
//设置 workbook.xml.rels insertWorkbookSheet(sourceSheet, destSheet, sheetId, rid, 'after');
rid := getWorkbookRelsRid(); insertDocPropsApp(sourceSheet, destSheet, 'after');
workbook_rels := GetXmlFileObj('xl/_rels/workbook.xml.rels'); setContentTypes(fname);
rels := workbook_rels.FirstChildElement('Relationships').InsertEndChild('element', 'Relationship');
rels.SetAttribute('Target', getTarget( sheetsCount_ + 1));
rels.SetAttribute('Type', class(TSXml).GetTemplate('RelationshipWorkSheet'));
rels.SetAttribute('Id', rid);
//workbook_rels.Print;
//设置 xl/workbook.xml
workbook := GetXmlFileObj('xl/workbook.xml');
node := workbook.FirstChildElement('workbook').FirstChildElement('sheets');
sheet_node := node.FirstChildElement('sheet');
while ifObj(sheet_node) do
begin
if sheet_node.GetAttribute('name') = sourceSheet then
begin
sheet_node := node.InsertAfterChild(sheet_node, 'element', 'sheet');
sheet_node.SetAttribute('name', destSheet);
sheet_node.SetAttribute('sheetId', sheetId);
sheet_node.SetAttribute('r:id', rid);
break;
end
sheet_node := sheet_node.NextElement();
end
//workbook.Print();
//设置docProps/app.xml
app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app'));
//app.Print();
node := app.FirstChildElement('Properties').FirstChildElement('TitlesOfParts');
vector := node.FirstChildElement('vt:vector');
vector.SetAttribute('size', length(sheetNames_) + 1);
lpstr := vector.FirstChildElement('vt:lpstr');
while ifObj(lpstr) do
begin
if LowerCase(lpstr.GetText()) = LowerCase(sourceSheet) then
begin
lpstr := vector.InsertAfterChild(lpstr, 'element', 'vt:lpstr');
lpstr.SetValue(destSheet);
break;
end
lpstr := lpstr.NextElement();
end
//设置[Content_Types].xml
content_xml := GetXmlFileObj(class(TSXml).GetFileName('Content_Types'));
class(TSXml).AddOverrideContentType(content_xml, '/' + fname, class(TSXml).GetTemplate('sheetContentType'));
ind := sheetIndexMap_[sname]; ind := sheetIndexMap_[sname];
for i:=sheetsCount_ downto ind+2 do for i:=sheetsCount_ downto ind+2 do
@@ -311,66 +375,12 @@ Type xlsxWorkBook = Class
sname := LowerCase(sourceSheet); sname := LowerCase(sourceSheet);
if not ifint(sheetIndexMap_[ sname ]) then return 'sourceSheet does not exists'; if not ifint(sheetIndexMap_[ sname ]) then return 'sourceSheet does not exists';
//添加文件xl/worksheets/sheetN.xml
sheetId := vselect maxof(['sheetId']) from sheetNames_ end;
sheetId := integer(sheetId) + 1;
fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml'; fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml';
zipfile_.Add(fname, class(TSXml).XmlHeader() + class(TSXml).GetTemplate('sheet1')); sheetId := addSheetN(fname);
rid := setWorkbookRels();
//设置 workbook.xml.rels insertWorkbookSheet(sourceSheet, destSheet, sheetId, rid, 'before');
rid := getWorkbookRelsRid(); insertDocPropsApp(sourceSheet, destSheet, 'before');
workbook_rels := GetXmlFileObj('xl/_rels/workbook.xml.rels'); setContentTypes(fname);
rels := workbook_rels.FirstChildElement('Relationships').InsertEndChild('element', 'Relationship');
rels.SetAttribute('Target', getTarget( sheetsCount_ + 1));
rels.SetAttribute('Type', class(TSXml).GetTemplate('RelationshipWorkSheet'));
rels.SetAttribute('Id', rid);
//workbook_rels.Print;
//设置 xl/workbook.xml
workbook := GetXmlFileObj('xl/workbook.xml');
node := workbook.FirstChildElement('workbook').FirstChildElement('sheets');
sheet_node := node.FirstChildElement('sheet');
prev_node := nil;
while ifObj(sheet_node) do
begin
if LowerCase(sheet_node.GetAttribute('name')) = LowerCase(sourceSheet) then
begin
if ifnil(prev_node) then sheet_node := node.InsertFirstChild('element', 'sheet');
else sheet_node := node.InsertAfterChild(prev_node, 'element', 'sheet');
sheet_node.SetAttribute('name', destSheet);
sheet_node.SetAttribute('sheetId', sheetId);
sheet_node.SetAttribute('r:id', rid);
break;
end
prev_node := sheet_node;
sheet_node := sheet_node.NextElement();
end
//workbook.Print();
//设置docProps/app.xml
app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app'));
//app.Print();
node := app.FirstChildElement('Properties').FirstChildElement('TitlesOfParts');
vector := node.FirstChildElement('vt:vector');
vector.SetAttribute('size', length(sheetNames_) + 1);
lpstr := vector.FirstChildElement('vt:lpstr');
pstr := nil;
while ifObj(lpstr) do
begin
if LowerCase(lpstr.GetText()) = LowerCase(sourceSheet) then
begin
if ifnil(pstr) then lpstr := vector.InsertFirstChild('element', 'vt:lpstr');
else lpstr := vector.InsertAfterChild(pstr, 'element', 'vt:lpstr');
lpstr.SetValue(destSheet);
break;
end
pstr := lpstr;
lpstr := lpstr.NextElement();
end
//设置[Content_Types].xml
content_xml := GetXmlFileObj(class(TSXml).GetFileName('Content_Types'));
class(TSXml).AddOverrideContentType(content_xml, '/' + fname, class(TSXml).GetTemplate('sheetContentType'));
ind := sheetIndexMap_[sname]; ind := sheetIndexMap_[sname];
for i:=sheetsCount_ downto ind+1 do for i:=sheetsCount_ downto ind+1 do
@@ -409,7 +419,8 @@ Type xlsxWorkBook = Class
for i:=0 to length(sheetNames_)-1 do Begin for i:=0 to length(sheetNames_)-1 do Begin
sheetNames_[i]['rid'] := 'rId' + inttostr(i + 1); //重置rId sheetNames_[i]['rid'] := 'rId' + inttostr(i + 1); //重置rId
oldname := sheetNames_[i]['file']; oldname := sheetNames_[i]['file'];
newname := sheetPrefix_ + inttostr(i + 1) + '.xml'; fdir := ExtractFileDir(oldname);
newname := fdir + "/" + "sheet" + inttostr(i + 1) + '.xml';
sheetNames_[i]['file'] := newname; sheetNames_[i]['file'] := newname;
if oldname <> newname then Begin if oldname <> newname then Begin
n := vselect thisrowindex from files where ['FileName'] = oldname end; n := vselect thisrowindex from files where ['FileName'] = oldname end;
@@ -463,7 +474,7 @@ Type xlsxWorkBook = Class
node.SetAttribute('sheetId', sheetNames_[i]['sheetId']); node.SetAttribute('sheetId', sheetNames_[i]['sheetId']);
node.SetAttribute('r:id', sheetNames_[i]['rid']); node.SetAttribute('r:id', sheetNames_[i]['rid']);
End; End;
//workbook.Print(); // workbook.Print();
//设置docProps/app.xml //设置docProps/app.xml
app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app')); app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app'));
@@ -512,15 +523,19 @@ Type xlsxWorkBook = Class
Function CopySheet(sourceSheet, destSheet); Function CopySheet(sourceSheet, destSheet);
Begin Begin
ind := sheetIndexMap_[ LowerCase(destSheet) ];
if ifint(ind) then return destSheet $ ' already exists.';
ind := sheetIndexMap_[ LowerCase(sourceSheet) ]; ind := sheetIndexMap_[ LowerCase(sourceSheet) ];
if not ifint(ind) then return sourceSheet $ ' does not exists.'; if not ifint(ind) then return sourceSheet $ ' does not exists.';
dest_ind := sheetIndexMap_[ LowerCase(destSheet) ];
//copy sheet //copy sheet
sheetId := vselect maxof(['sheetId']) from sheetNames_ end; if ifint(dest_ind) then
sheetId := integer(sheetId) + 1; begin
fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml'; fname := sheetNames_[dest_ind]['file'];
zipfile_.Remove(fname);
end
else begin
fname := sheetPrefix_ $ inttostr(sheetsCount_ + 1) $ '.xml';
end
sheet := GetSheetXmlFile(sourceSheet); sheet := GetSheetXmlFile(sourceSheet);
zipfile_.Add(fname, sheet.Data()); zipfile_.Add(fname, sheet.Data());
xml_file := GetXmlFileObj(fname); xml_file := GetXmlFileObj(fname);
@@ -549,7 +564,14 @@ Type xlsxWorkBook = Class
sheet_rels := GetSheetRelsFile(sourceSheet); sheet_rels := GetSheetRelsFile(sourceSheet);
if ifObj(sheet_rels) then if ifObj(sheet_rels) then
begin begin
rels_name := 'xl/worksheets/_rels/' + 'sheet' + inttostr(sheetsCount_ + 1) + '.xml.rels'; if ifint(dest_ind) then
begin
rels_name := 'xl/worksheets/_rels/' + ExtractFileName(sheetNames_[dest_ind]['file']) + '.rels';
zipfile_.Remove(rels_name);
end
else begin
rels_name := 'xl/worksheets/_rels/' + 'sheet' + inttostr(sheetsCount_ + 1) + '.xml.rels';
end
zipfile_.Add(rels_name, sheet_rels.Data()); zipfile_.Add(rels_name, sheet_rels.Data());
rels_file := GetXmlFileObj(rels_name); rels_file := GetXmlFileObj(rels_name);
relationship := rels_file.FirstChildElement('Relationships').FirstChildElement('Relationship'); relationship := rels_file.FirstChildElement('Relationships').FirstChildElement('Relationship');
@@ -576,6 +598,8 @@ Type xlsxWorkBook = Class
end end
end end
if ifint(dest_ind) then return;
//workbook.xml.rels //workbook.xml.rels
rid := getWorkbookRelsRid(); rid := getWorkbookRelsRid();
workbook_rels := GetXmlFileObj('xl/_rels/workbook.xml.rels'); workbook_rels := GetXmlFileObj('xl/_rels/workbook.xml.rels');
@@ -585,6 +609,8 @@ Type xlsxWorkBook = Class
rels.SetAttribute('Id', rid); rels.SetAttribute('Id', rid);
//xl/workbook.xml //xl/workbook.xml
sheetId := vselect maxof(['sheetId']) from sheetNames_ end;
sheetId := integer(sheetId) + 1;
workbook := GetXmlFileObj('xl/workbook.xml'); workbook := GetXmlFileObj('xl/workbook.xml');
node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').InsertEndChild('element','sheet'); node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').InsertEndChild('element','sheet');
node.SetAttribute('name', destSheet); node.SetAttribute('name', destSheet);
@@ -593,9 +619,17 @@ Type xlsxWorkBook = Class
//app.xml //app.xml
app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app')); app := GetXmlFileObj(class(TSXml).GetFileName('docProps_app'));
vector := app.FirstChildElement('Properties').FirstChildElement('TitlesOfParts').FirstChildElement('vt:vector'); prop := app.FirstChildElement('Properties');
vector.SetAttribute('size', sheetId); vector := prop.FirstChildElement('TitlesOfParts').FirstChildElement('vt:vector');
vector.SetAttribute('size', sheetsCount_+1);
vector.InsertEndChild('element', 'vt:lpstr', destSheet); vector.InsertEndChild('element', 'vt:lpstr', destSheet);
vector := prop.FirstChildElement('HeadingPairs').FirstChildElement('vt:vector');
if ifObj(vector) then
begin
variant := vector.FirstChildElement('vt:variant').NextElement('vt:variant');
i4 := variant.FirstChildElement('vt:i4');
i4.SetValue(sheetsCount_ + 1);
end
//[Content_Types].xml //[Content_Types].xml
content_xml := GetXmlFileObj(class(TSXml).GetFileName('Content_Types')); content_xml := GetXmlFileObj(class(TSXml).GetFileName('Content_Types'));
@@ -726,23 +760,25 @@ Type xlsxWorkBook = Class
Function SetSheetVisible(sheet, visible); Function SetSheetVisible(sheet, visible);
Begin Begin
workbook := GetXmlFileObj('xl/workbook.xml'); workbook := GetXmlFileObj('xl/workbook.xml');
node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').FirstChildElement('sheet'); node := class(TSXml).GetNode(workbook, 'workbook/sheets/sheet');
hidden := visible = 1 ? 0 : 1; if GetSheetsCount() = 1 then return "Only one sheet, can't set visible.";
default_sheet_name := GetDefaultSheet(); sheet := lowercase(sheet);
if default_sheet_name = sheet then default_sheet_name := lowercase(GetDefaultSheet());
if default_sheet_name = sheet and not visible then
begin begin
ind := sheetIndexMap_[LowerCase(default_sheet_name)]; ind := sheetIndexMap_[LowerCase(default_sheet_name)];
if ind = 0 then default_name := sheetNames_[ind + 1]['name']; default_name := ind = 0 ? sheetNames_[1]['name'] : sheetNames_[ind - 1]['name'];
else default_name := sheetNames_[ind - 1]['name'];
SetDefaultSheet(default_name); SetDefaultSheet(default_name);
end end
if visible then SetDefaultSheet(sheet);
state := visible ? "nohidden" : "hidden";
while ifObj(node) do while ifObj(node) do
Begin Begin
name := node.GetAttribute('name'); name := lowercase(node.GetAttribute('name'));
if name = sheet then if name = sheet then
Begin Begin
if hidden then node.SetAttribute('state', 'hidden'); node.SetAttribute('state', state);
else node.DeleteAttribute('state'); break;
End End
node := node.NextElement(); node := node.NextElement();
End End
@@ -753,11 +789,12 @@ Type xlsxWorkBook = Class
Begin Begin
sheet_file := GetSheetXmlFile(sheet); sheet_file := GetSheetXmlFile(sheet);
if not ifObj(sheet_file) then return 0; if not ifObj(sheet_file) then return 0;
sheet := lowercase(sheet);
workbook := GetXmlFileObj('xl/workbook.xml'); workbook := GetXmlFileObj('xl/workbook.xml');
node := workbook.FirstChildElement('workbook').FirstChildElement('sheets').FirstChildElement('sheet'); node := class(TSXml).GetNode(workbook, 'workbook/sheets/sheet');
while ifObj(node) do while ifObj(node) do
Begin Begin
name := node.GetAttribute('name'); name := lowercase(node.GetAttribute('name'));
if name = sheet then if name = sheet then
Begin Begin
val := node.GetAttribute('state'); val := node.GetAttribute('state');
@@ -863,6 +900,11 @@ Type xlsxWorkBook = Class
Function SetRowHeight(sheet, row, height); Function SetRowHeight(sheet, row, height);
Begin Begin
obj := GetSheetObj(sheet); obj := GetSheetObj(sheet);
if not obj.RowIsExists(row) then
begin
axis := CoordinatesToCellName(1, row, False)[1];
if not obj.CellIsExists(axis) then SetCellValue(sheet, axis, '');
end
obj.SetAttribute(row, array('ht': height, "customHeight": 1)); obj.SetAttribute(row, array('ht': height, "customHeight": 1));
End End
@@ -952,7 +994,7 @@ Type xlsxWorkBook = Class
col_node := work_node.FirstChildElement('cols'); col_node := work_node.FirstChildElement('cols');
default_width := work_node.FirstChildElement('sheetFormatPr').GetAttribute('defaultColWidth'); default_width := work_node.FirstChildElement('sheetFormatPr').GetAttribute('defaultColWidth');
default_width := trystrtofloat(default_width, r) ? r: -1; default_width := trystrtofloat(default_width, r) ? r: -1;
if not ifObj(col_node) then return array(0, default_width); if not ifObj(col_node) then return nil;
col_number := ColumnNameToNumber(col)[1]; col_number := ColumnNameToNumber(col)[1];
node := col_node.FirstChildElement('col'); node := col_node.FirstChildElement('col');
@@ -1104,29 +1146,17 @@ Type xlsxWorkBook = Class
node := sheet_node.InsertFirstChild('element', 'sheetView'); node := sheet_node.InsertFirstChild('element', 'sheetView');
node.SetAttribute('workbookViewId', 0); node.SetAttribute('workbookViewId', 0);
end end
if name = sheet then if lowercase(name) = lowercase(sheet) then
Begin Begin
node.SetAttribute('tabselected', 1); node.SetAttribute('tabSelected', 1);
workbook := GetXmlFileObj('xl/workbook.xml'); workbook := GetXmlFileObj('xl/workbook.xml');
workbook_node := workbook.FirstChildElement('workbook'); view_node := class(TSXml).GetNode(workbook, 'workbook/bookViews/workbookView');
book_view_node := workbook_node.FirstChildElement('bookViews');
if not ifObj(book_view_node) then
begin
prev_node := class(TSXml).GetWorkBookPrevNode(workbook_node, 'bookViews');
if not ifObj(prev_node) then book_view_node := workbook_node.InsertFirstChild('element', 'bookViews');
else book_view_node := workbook_node.InsertAfterChild(prev_node, 'element', 'bookViews');
end;
view_node := book_view_node.FirstChildElement('workbookView');
if not ifObj(view_node) then
begin
view_node := book_view_node.InsertFirstChild('element', 'workbookView');
end
view_node.SetAttribute('activeTab', ind); view_node.SetAttribute('activeTab', ind);
End End
else else
begin begin
node := root_node.FirstChildElement('sheetViews').FirstChildElement('sheetView'); node := root_node.FirstChildElement('sheetViews').FirstChildElement('sheetView');
node.SetAttribute('tabselected', 0); node.SetAttribute('tabSelected', 0);
end end
end end
End End
@@ -1464,7 +1494,7 @@ Type xlsxWorkBook = Class
if col >= min and col <= max then if col >= min and col <= max then
Begin Begin
level_val := node.GetAttribute('outlineLevel'); level_val := node.GetAttribute('outlineLevel');
if strtoint(level_val) = level then return; if trystrtoint(level_val, r) and r = level then return;
else Begin else Begin
if col = min and col = max then node.SetAttribute('outlineLevel', level); if col = min and col = max then node.SetAttribute('outlineLevel', level);
else begin else begin
@@ -1580,9 +1610,9 @@ private
Function copyFile(obj, target, content); Function copyFile(obj, target, content);
Begin Begin
file_name := ReplaceStr(target, '..', 'xl'); file_name := ReplaceStr(target, '..', 'xl');
counts := GetFilesCount(ReplaceStrByReg(file_name, "\\d+.*ml", '')) + 1; counts := GetFilesCount(ReplaceStrUsingReg(file_name, "\\d+.*ml", '')) + 1;
xml := GetXmlFileObj(file_name); xml := GetXmlFileObj(file_name);
new_file_postfix := ReplaceStrByReg(file_name[3:], "\\d+", inttostr(counts)); new_file_postfix := ReplaceStrUsingReg(file_name[3:], "\\d+", inttostr(counts));
zipfile_.Add('xl' + new_file_postfix, xml.Data()); zipfile_.Add('xl' + new_file_postfix, xml.Data());
obj.SetAttribute('Target', '..' + new_file_postfix); obj.SetAttribute('Target', '..' + new_file_postfix);
@@ -1594,11 +1624,22 @@ private
return array(counts, 'xl' + new_file_postfix); return array(counts, 'xl' + new_file_postfix);
End; End;
function ReplaceStrUsingReg(s, regFromText, toText);
begin
ParseCtrls := 'r';
if ifnil(toText) then toText := '';
ParseRegExpr(RegFromText,s,ParseCtrls,toText,s2);
if ansicontainstext(ParseCtrls,'r') then //表替换,输出s2
return ifstring(s2)?s2:s;
else
return ifArray(toText) and length(toText) > 0 ? toText : array();
end;
sheetsCount_:integer; sheetsCount_:integer;
sheetNames_; sheetNames_;
sheetIndexMap_; sheetIndexMap_;
sheetPrefix_:string; sheetPrefix_:string;
zipfile_; [weakref]zipfile_;
xmlFileObjMap_; //XmlFile对象存储 xmlFileObjMap_; //XmlFile对象存储
sheetObjMap_; //XmlSheet对象存储 sheetObjMap_; //XmlSheet对象存储
End; End;
+460 -22
View File
@@ -1,5 +1,443 @@
# 更新日志 # 更新日志
## 2026-09-10
### V1.8.8
#### word
1. 修复`InsertFile`时,图片前有空格无法识别问题
## 2026-07-30
### V1.8.7
#### word
1. 修复`InsertFile`时,样式重复导致wps/word识别失败从而渲染错误问题
## 2026-01-16
### V1.8.6
修复语法问题
#### word
1. 修复`InsertTable`多行数据插入缺失问题
## 2025-12-15
### V1.8.5
#### word
1. 修复插入word时,单元格内容不完整问题
#### excel
1. 修复`GetColWithd`返回值出现数组问题,没有设置宽度返回`nil`
## 2025-11-07
### V1.8.4
#### word
1. 修复合并单元格时候设置属性不规范
## 2025-10-30
### V1.8.3
#### word
1. `setData`移除`fieldNames`依赖
#### excel
1. `InsertTable/GetTable`移除`fieldNames` 依赖
## 2025-10-29
### V1.8.2
#### word
1. 升级段落判空`Empty`
2. 修复`FileName`总是返回 gbk
#### excel
1. 修复`CopySheet`依赖的`ReplaceStrByReg`公共方法问题,不再依赖该方法
2. 修复`FileName`总是返回 gbk
## 2025-7-22
### V1.8.1
#### word
1. **feat**: 支持同一段落多图片文字
```cpp
picture := TOfficeObj('TPicture');
picture.Descr := '';
picture.Image := TOfficeTemplate('tinysoft.gif',true);
docx := new TSDocxFile();
docx.NewFile();
p := new TOfficeObj('TParagraph');
r := p.AddRun();
r.SetText("abc");
r := p.AddRun();
r.SetDrawing(picture, docx); // 需要一个图片对象和TSDocxFile对象
r := p.AddRun();
r.SetText("def");
docx.AddParagraph(p, -1);
```
## 2025-6-23
### V1.8.0
#### word
1. **feat**: 支持添加自定目录`TSDocxFile.AddCustomTableContent`
2. **fix**: 修复单元格内容换行,自定义属性失效问题
## 2025-2-28
### V1.7.9
#### word
1. **feat**:支持目录自定义宽度`TOfficeApi().Get("TTableContent-tab-position")`
2. **fix**:插入图片 id 计算错误,导致`office 2016 16.0.4266`版本不兼容
## 2025-1-22
### V1.7.8
❗ 解决`TSDocxFile``TSXlsxFile`内存泄露
#### word
1. **fix**`CreateTable`由于`fieldnames.tsf`差异报错
## 2025-1-17
### V1.7.7
#### word
1. **feat**`TPicture`对象设置画布大小`CanvasWidth``CanvasHeight`
2. **fix**`InsertTable`表格数据不对齐报错
#### excel
1. **fix**`SetColOutlineLevel`错误
## 2025-1-8
### V1.7.6
#### excel
1. **fix**`SetRowHeight`单元格不存在无法设置
2. **fix**`Set[Get]ColVisible`修改传入的列参数
## 2025-1-7
### V1.7.5
#### word
1. 支持获取`sdt`标签类型的内容(如文本框),通过`TSDocxFile.Sdts()`获取文档的的所有`sdt`
> ```pascal
> sdts := docx.Sdts();
> paragraphs := sdts[0].Paragraphs();
> textbox := paragraphs[1].TextBoxs();
> ```
## 2024-12-23
### V1.7.4
#### word
1. `insertfile`时候默认添加`w16du`命名空间
## 2024-12-05
### V1.7.3
#### word
1. `insertfile`支持 ole 对象的插入,如 wmf 公式,excel 表格
## 2024-12-04
### V1.7.2
#### word
1. 支持单元格标题生成到目录,需要额外设置`TOfficeApi().SetCellTableContent(true);`,默认是`false`
## 2024-11-19
### V1.7.1
#### word
1. 对生成目录的 xml 结构进行更改
2. 修复引用 excel 错误
#### excel
1. 修复获取`comment`时候,换行符问题
## 2024-7-8
### V1.7.0
#### excel
1. 修复`CopySheet`操作后,文件报错问题
## 2024-5-6
### V1.6.9
#### excel
1. 修复单元格继承列样式失败问题
## 2024-4-12
### V1.6.8
### excel
1. 修复`SetCellValue`单元格对列样式的识别,不需要手动用格式刷对所有单元格刷新样式
## 2024-3-21
### V1.6.7
#### word
1. 新增对象的`Delete`方法,可以通过`Delete(name)`删除对象的指定属性
2. 新增`TPageNumType`对象
3. 扩展`TDocSection`方法,`AppendReference``AddReference`,前者是对已有的`Section`对象添加`TReference`对象,而后者是对新的`Section`对象添加
## 2024-3-14
### V1.6.6
#### word
1. 修复`TDocSection`节点获取错误
2. 支持分栏自定义宽度
## 2024-3-4
### V1.6.5
支持扩展扩展模块
### excel
1. 样式获取报错问题
### V1.6.4
#### word
1. 修复`InsertTable`内容`\n`无换行问题
2. `TextBox`支持`Clear`清空内容
#### word
1. 修复目录生成陷入死循环问题
## 2024-2-23
### V1.6.3
#### word
1. 修复目录生成陷入死循环问题
## 2024-2-7
### V1.6.2
#### word
1. 修复设置段落属性`TextAlignment`失败问题
## 2024-2-5
### V1.6.1
#### excel
1. 修复 excel 文件单元格原有类型与 tsl 类型转换报错问题(trystrtofloat)
## 2024-2-5
### V1.6.0
#### excel
1. 兼容 Excel2016,通过`NewSheet/InsertSheet`创建工作表不再提示修复错误
2. 修复带有表头的二维数组通过`InsertTable`写入数据只写入表头未写入数据问题
## 2024-1-31
### V1.5.9
修复`tsl`脚本格式为`utf8`时无法打开中文命名的文件
### V1.5.8
#### excel
1. 支持写入单元格内容时判断当前单元格的数据类型,并以单元格数据类型为准
## 2024-1-17
### V1.5.7
#### excel
1. 修复单元格写入浮点数数据 bug,如写入 0.0,excel 某些版本打开会显示 0.00000000000000000
## 2024-1-11
### V1.5.6
#### excel
1. 修复单元格写入浮点数数据,精度丢失问题
## 2023-12-29
### V1.5.5
#### word
1. 修复生成的目录打开后重新生成页码可能产生页码失败问题
#### excel
1. 修复`InsertTable`与``SetCellValue`返回值问题
## 2023-12-18
### V1.5.4
#### excel
1. 优化`InsertTable`的写入效率
## 2023-12-11
### V1.5.3
#### excel
1. 支持写入单元格时且单元格不存在时,新的单元格会沿用设置的样式 ID(若有设置)
## 2023-12-1
### V1.5.2
#### excel
1. 修复公式中文转码问题
## 2023-11-15
### V1.5.1
1. 支持识别图片中含有`0xffc2`段的 jpg 格式的大小
## 2023-11-14
### V1.5.0
#### word
1. 新增对脚注的支持,方法`TSDocxFile.FootnotesObject().Add`
2. `TSDocxFile.InsertFile`支持脚注插入
### excel
1. 升级`TSXlsxFile.CopySheet`
## 2023-10-16
### V1.4.9
#### word
1. 新增`TSDocxFile.InsertFile`重载方法
2. 新增`Table.SetStyle`方法
## 2023-9-27
### V1.4.8
#### word
1. 支持`Inserttable`时候加入对单元格样式的设置
2. 新增`TSDocxFile.LastParagraph`方法
3. 新增`TParagraph.PrevParagraph`方法
4. 性能优化
## 2023-9-22
### V1.4.7
#### word
1. 修复项目符号属于样式时,生成目录无法识别出项目符号问题
## 2023-9-19
### V1.4.6
#### word
1. 修复表格存在合并单元格,生成目录报错问题
2. 修复单元格添加 run 对象,设置样式不生效问题
3. 修复插入 word 后,中文样式重复问题
### excel
🔔 重要升级:`TSExcelFile`更名为`TSXlsxFile`,建议更改,旧名字现阶段仍可使用
1. 整理`NewSheet``SetSheetVisible`代码
#### excel
1. 修复`NewSheet`excel 打开遇到提示错误问题
## 2023-8-30
### V1.4.5
#### word
1. 支持生成目录后返回目录对象的所有段落内容`目录对象.Paragraphs()`
#### excel
1. 修复`NewSheet`excel 打开遇到提示错误问题
## 2023-8-28 ## 2023-8-28
### V1.4.4 ### V1.4.4
@@ -8,7 +446,7 @@
1. 修复`insertFile`样式错误问题 1. 修复`insertFile`样式错误问题
2. 修复`insertFile`后删除段落再新增段落位置错误问题 2. 修复`insertFile`后删除段落再新增段落位置错误问题
3. 修复生成目录中文编码未转换导致word打开失败问题 3. 修复生成目录中文编码未转换导致 word 打开失败问题
## 2023-8-22 ## 2023-8-22
@@ -24,7 +462,7 @@
#### word #### word
支持插入另一个word内容`InsertFile(alias, fileName, posOpt)` 支持插入另一个 word 内容`InsertFile(alias, fileName, posOpt)`
## 2023-8-11 ## 2023-8-11
@@ -32,7 +470,7 @@
#### word #### word
修复插入表格后,设置样式ID无法全部生效问题 修复插入表格后,设置样式 ID 无法全部生效问题
## 2023-8-10 ## 2023-8-10
@@ -40,7 +478,7 @@
#### word #### word
支持三级以内目录设置字体,一级目录样式ID为`TOC1`,二级目录样式ID为`TOC2`,三级为`TOC3`,通过样式设置相关属性即可修改目录字体 支持三级以内目录设置字体,一级目录样式 ID `TOC1`,二级目录样式 ID `TOC2`,三级为`TOC3`,通过样式设置相关属性即可修改目录字体
## 2023-8-7 ## 2023-8-7
@@ -48,7 +486,7 @@
#### word #### word
支持`AddHeading`时传入样式Id 支持`AddHeading`时传入样式 Id
## 2023-8-2 ## 2023-8-2
@@ -80,13 +518,13 @@
#### word #### word
段落字体大小设置调整,对齐VBA设置 段落字体大小设置调整,对齐 VBA 设置
## 2023-7-11 ## 2023-7-11
### V1.3.4 ### V1.3.4
修复加密Bug 修复加密 Bug
## 2023-7-4 ## 2023-7-4
@@ -98,11 +536,11 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
### V1.3.2 ### V1.3.2
修复.net使用rdo2执行失败问题,使用rdo2时候,需调用`TOfficeInit()`初始化 修复.net 使用 rdo2 执行失败问题,使用 rdo2 时候,需调用`TOfficeInit()`初始化
#### word #### word
1. 修复word模板`template.docx`执行失败问题 1. 修复 word 模板`template.docx`执行失败问题
## 2023-6-20 ## 2023-6-20
@@ -122,7 +560,7 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
#### excel #### excel
1. 支持excel程序设置字体样式粗体,斜体等此类问题的返回类型,如`style.Font.Bold`返回`true 或 false` 1. 支持 excel 程序设置字体样式粗体,斜体等此类问题的返回类型,如`style.Font.Bold`返回`true 或 false`
## 2023-4-4 ## 2023-4-4
@@ -138,7 +576,7 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
#### excel #### excel
1. 修复由.net客户端导出的excel兼容性问题,`SetColWidth``Set/GetDefaultSheet``SetSheetHeaderFooter` 1. 修复由.net 客户端导出的 excel 兼容性问题,`SetColWidth``Set/GetDefaultSheet``SetSheetHeaderFooter`
## 2023-3-23 ## 2023-3-23
@@ -207,7 +645,7 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
#### excel #### excel
1. Get相关方法重新Set后不再覆盖原有设置,影响方法如下`Set(Get)PageMargins`,`Set(Get)CellHyperLink`,`Set(Get)PageLayout`,`Set(Get)CalcOptions`,`Set(Get)DefaultFont`,`Set(Get)SheetViewOptions` 1. Get 相关方法重新 Set 后不再覆盖原有设置,影响方法如下`Set(Get)PageMargins`,`Set(Get)CellHyperLink`,`Set(Get)PageLayout`,`Set(Get)CalcOptions`,`Set(Get)DefaultFont`,`Set(Get)SheetViewOptions`
## 2023-2-23 ## 2023-2-23
@@ -244,7 +682,7 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
1. 新增`LoadFromMem`, `SavaToMem` 1. 新增`LoadFromMem`, `SavaToMem`
2. 新增重载方法`NewSheet` 2. 新增重载方法`NewSheet`
3. 新增`SetCalcOptions` 3. 新增`SetCalcOptions`
4. 修复删除sheet报错问题 4. 修复删除 sheet 报错问题
## 2023-2-13 ## 2023-2-13
@@ -280,7 +718,7 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
#### word #### word
1. 修复获取段落样式ID失败问题 1. 修复获取段落样式 ID 失败问题
2. 修复文本框添加图片失败问题 2. 修复文本框添加图片失败问题
#### excel #### excel
@@ -337,8 +775,8 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
#### word #### word
1. 新增ExecInnerTSl 1. 新增 ExecInnerTSl
2. 新增修改chart图(数据) 2. 新增修改 chart 图(数据)
3. 修复`TNumbering::AddStyleByInnerXml`错误 3. 修复`TNumbering::AddStyleByInnerXml`错误
4. 完善帮助文档 4. 完善帮助文档
@@ -356,11 +794,11 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
#### word #### word
1. 修复chart图兼容性问题 1. 修复 chart 图兼容性问题
### V1.0.6 ### V1.0.6
中文自动转换API由`class(xlsxXml).CodePage('中文');`调整为`TOfficeApi().CodePage('中文');` 中文自动转换 API `class(xlsxXml).CodePage('中文');`调整为`TOfficeApi().CodePage('中文');`
## 2023-1-5 ## 2023-1-5
@@ -370,15 +808,15 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
#### word #### word
1. 修复 Properties执行报错 1. 修复 Properties 执行报错
2. 修复格式刷 2. 修复格式刷
#### excel #### excel
1. 移除API `JoinCellName` 1. 移除 API `JoinCellName`
2. 修改`RGBToHSL``HSLToRGB`返回值 2. 修改`RGBToHSL``HSLToRGB`返回值
3. 修复获取超链接`GetCellHyperLink`失败问题 3. 修复获取超链接`GetCellHyperLink`失败问题
4. 修复一个对象新建文件,打开文件之后引发的xlsx文件错误问题 4. 修复一个对象新建文件,打开文件之后引发的 xlsx 文件错误问题
5. 修复`GetCoreProps`,`GetAppProps`失败问题 5. 修复`GetCoreProps`,`GetAppProps`失败问题
## 2022-12-30 ## 2022-12-30
@@ -398,4 +836,4 @@ word/excel 新增加密方法`SetPassword`,升级`OpenFile(alias, fileName, Pa
5. 修复`SetRowVisible``GetRowVisible``SetSheetVisible`问题 5. 修复`SetRowVisible``GetRowVisible``SetSheetVisible`问题
如何设置字符集(中文支持)? 如何设置字符集(中文支持)?
★用户的脚本可能是UFT8格式,或可能是GBK码格式,系统提供API自动设置当前字符集环境:`class(xlsxXml).CodePage('中文');` 在文件头设置该代码后,系统会自动检测当前的环境字符集 用户的脚本可能是 UFT8 格式,或可能是 GBK 码格式,系统提供 API 自动设置当前字符集环境:`class(xlsxXml).CodePage('中文');` 在文件头设置该代码后,系统会自动检测当前的环境字符集