Compare commits

...
92 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 15e2cbe661 整理word内容作为unit 2023-12-07 13:41:06 +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
csh 3643be6231 update 2023-08-29 15:05:06 +08:00
csh e2e68efc30 Merge branch 'master' into word 2023-08-29 15:00:42 +08:00
csh ef0dcde062 v1.4.4-patch2 2023-08-29 11:33:57 +08:00
csh ba5f255573 v1.4.4-patch1 2023-08-28 17:54:56 +08:00
csh 79ba3254a0 v1.4.4 2023-08-28 17:17:15 +08:00
csh 81b806c93c v1.4.3-patch2 2023-08-25 16:37:07 +08:00
csh 60847b0636 v1.4.3-patch1 2023-08-25 10:54:54 +08:00
csh 819efc1ee1 v1.4.3 2023-08-22 14:33:57 +08:00
csh 9037124c01 v1.4.2-patch1 2023-08-18 18:05:48 +08:00
csh b59c869ae2 v1.4.2 2023-08-18 16:49:12 +08:00
csh 8d63ecd7b3 v1.4.1 2023-08-11 16:27:15 +08:00
csh f781cd0c0a v1.4.0-patch2 2023-08-10 17:36:28 +08:00
csh 522142b712 v1.4.0-patch1 2023-08-10 15:24:47 +08:00
csh 6eec96d84d v1.4.0 2023-08-10 15:24:30 +08:00
csh 1abc2028fe v1.3.9 2023-08-07 15:52:57 +08:00
csh 1d0b5684cc v1.3.8-patch1 2023-08-02 17:24:10 +08:00
csh 0c73a4c0d1 v1.3.8 2023-08-02 16:32:01 +08:00
csh ced0d6b04c v1.3.7 2023-07-26 14:35:05 +08:00
csh 880e03c41a v1.3.6 2023-07-19 17:47:54 +08:00
csh 2384ca42b5 Merge branch 'master' into word 2023-07-14 10:37:15 +08:00
csh 845c6bb554 v1.3.5 2023-07-14 10:33:49 +08:00
csh f34d03a50f v1.3.4 2023-07-11 15:11:36 +08:00
csh ff6d23090e v1.3.3-patch1 2023-07-04 14:40:50 +08:00
csh f46240850e v1.3.3 2023-07-04 14:16:27 +08:00
csh ce331f4417 v1.3.2 2023-06-26 11:08:48 +08:00
csh c706d2d8d0 v1.3.2 2023-06-20 18:17:39 +08:00
csh 0e21645b2a v1.3.1-patch1 2023-06-05 17:08:00 +08:00
69 changed files with 15515 additions and 12113 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
+25 -23
View File
@@ -69,9 +69,11 @@ _Annotation(docx);
_Faq(docx); _Faq(docx);
///目录 ///目录
docx.AddTableContent(paragraphTitle, 1, 3); content := docx.AddTableContent(paragraphTitle, 1, 3);
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);
@@ -84,7 +86,7 @@ Function _0_AddTitle(docx);
Begin Begin
_PrintMsg('AddTitle'); _PrintMsg('AddTitle');
p := _AddTitle(docx, '天软DOCX文档操作接口帮助文档', 0);//添加文档标题 p := _AddTitle(docx, '天软DOCX文档操作接口帮助文档', 0);//添加文档标题
p.Font.Size := 48; p.Font.Size := 24;
p.Apply(); p.Apply();
for i:=0 to 16 do for i:=0 to 16 do
docx.AddLineBreak(-1);//换行符 docx.AddLineBreak(-1);//换行符
@@ -132,7 +134,7 @@ Begin
preface.Font.Name := '宋体'; preface.Font.Name := '宋体';
preface.Font.Color := 'FF0000'; preface.Font.Color := 'FF0000';
preface.Font.Bold := true; preface.Font.Bold := true;
preface.Font.Size := 32; preface.Font.Size := 16;
p1 := docx.AddParagraph(preface, -1, nil); p1 := docx.AddParagraph(preface, -1, nil);
println(' >>OK\n'); println(' >>OK\n');
@@ -303,7 +305,7 @@ Begin
p1.Run.SetText('本文档由天软科技制作。'); p1.Run.SetText('本文档由天软科技制作。');
p1.Run.rPr.Name := '宋体'; p1.Run.rPr.Name := '宋体';
p1.Run.rPr.Bold := true; p1.Run.rPr.Bold := true;
p1.Run.rPr.Size := 32; p1.Run.rPr.Size := 16;
p1.Run.rPr.Color := 'FF0000'; p1.Run.rPr.Color := 'FF0000';
p2 := docx.AddParagraph(p1, -1, nil); p2 := docx.AddParagraph(p1, -1, nil);
//插入批注 //插入批注
@@ -391,7 +393,7 @@ Begin
p1.Run.SetText( '插入案例。' ); p1.Run.SetText( '插入案例。' );
p1.Run.rPr.Name := '宋体'; p1.Run.rPr.Name := '宋体';
p1.Run.rPr.Bold := true; p1.Run.rPr.Bold := true;
p1.Run.rPr.Size := 32; p1.Run.rPr.Size := 16;
p1.Run.rPr.Color := 'FF0000'; p1.Run.rPr.Color := 'FF0000';
pAddRevision := docx.AddParagraph(p1, -1, nil); pAddRevision := docx.AddParagraph(p1, -1, nil);
//插入修订 //插入修订
@@ -410,7 +412,7 @@ Begin
p1.Run.SetText( '删除修订案例。' ); p1.Run.SetText( '删除修订案例。' );
p1.Run.rPr.Name := '宋体'; p1.Run.rPr.Name := '宋体';
p1.Run.rPr.Bold := true; p1.Run.rPr.Bold := true;
p1.Run.rPr.Size := 32; p1.Run.rPr.Size := 16;
p1.Run.rPr.Color := 'FF0000'; p1.Run.rPr.Color := 'FF0000';
pDelRevision := docx.AddParagraph(p1, -1, nil); pDelRevision := docx.AddParagraph(p1, -1, nil);
//删除修订 //删除修订
@@ -500,7 +502,7 @@ Begin
help.Font.Name := '宋体'; help.Font.Name := '宋体';
help.Font.Color := 'FF0000'; help.Font.Color := 'FF0000';
help.Font.Bold := true; help.Font.Bold := true;
help.Font.Size := 30; help.Font.Size := 15;
p1 := docx.AddParagraph(help, -1, nil); p1 := docx.AddParagraph(help, -1, nil);
section := docx.Sections(-1);//获取缺省章节 section := docx.Sections(-1);//获取缺省章节
@@ -514,10 +516,10 @@ Begin
p.Format.SpaceAfter := 0; p.Format.SpaceAfter := 0;
p.Font.Name := '宋体'; p.Font.Name := '宋体';
p.Font.Color := 'FF0000'; p.Font.Color := 'FF0000';
p.Font.Size := 16; p.Font.Size := 8;
p2 := footer.AddParagraph(p, -1, nil); p2 := footer.AddParagraph(p, -1, nil);
p.Font.Size := 18; p.Font.Size := 8;
pgno := footer.AddPageNumber('第 {0} 页,共 {1} 页', p.Font); //添加页码 pgno := footer.AddPageNumber('第 {-3} 页,共 {1} 页', p.Font); //添加页码
pgno.Format.Alignment := 'center'; //据中对齐 pgno.Format.Alignment := 'center'; //据中对齐
pgno.Format.SpaceAfter := 0; pgno.Format.SpaceAfter := 0;
pgno.Apply(); pgno.Apply();
@@ -530,7 +532,7 @@ Begin
//p.Format.Bdr.Bottom.val := 'single';//页眉横线 //p.Format.Bdr.Bottom.val := 'single';//页眉横线
p.Font.Name := '宋体'; p.Font.Name := '宋体';
p.Font.Color := 'FF0000'; p.Font.Color := 'FF0000';
p.Font.Size := 16; p.Font.Size := 8;
p1 := header.AddParagraph(p, -1, nil); p1 := header.AddParagraph(p, -1, nil);
println(' >>OK\n'); println(' >>OK\n');
@@ -583,19 +585,19 @@ Begin
pTest := docx.AddParagraph(p1, -1, nil); pTest := docx.AddParagraph(p1, -1, nil);
//修改部分文字字体 //修改部分文字字体
range := pTest.Range(3,2); range := pTest.Range(3,2);
range.Font.Size := 32; range.Font.Size := 16;
range.Font.Color := 'FF0000'; range.Font.Color := 'FF0000';
range.Font.Bold := true; range.Font.Bold := true;
range.Apply(); range.Apply();
//添加文字1 //添加文字1
range1 := pTest.AddText(5, '科技开发有限'); range1 := pTest.AddText(5, '科技开发有限');
range1.Font.Size := 28; range1.Font.Size := 14;
range1.Font.Color := '00FF00'; range1.Font.Color := '00FF00';
range1.Font.Bold := true; range1.Font.Bold := true;
range1.Apply(); range1.Apply();
//添加文字2 //添加文字2
range2 := pTest.AddText(0, '广东省'); range2 := pTest.AddText(0, '广东省');
range2.Font.Size := 28; range2.Font.Size := 14;
range2.Font.Color := '0000FF'; range2.Font.Color := '0000FF';
range2.Font.Bold := true; range2.Font.Bold := true;
range2.Apply(); range2.Apply();
@@ -603,7 +605,7 @@ Begin
//r.Text := 'Tinysoft'; //r.Text := 'Tinysoft';
r := pTest.AddText(-1, ':www.tinysoft.com.cn');//段落后追加 r := pTest.AddText(-1, ':www.tinysoft.com.cn');//段落后追加
r.Font.Size := 20; r.Font.Size := 10;
r.Font.Color := '0000FF'; r.Font.Color := '0000FF';
r.Font.Bold := true; r.Font.Bold := true;
r.Apply(); r.Apply();
@@ -656,7 +658,7 @@ Begin
p := TOfficeObj('TParagraph'); p := TOfficeObj('TParagraph');
p.Format.numPr.Level := 0;//项目编号 p.Format.numPr.Level := 0;//项目编号
p.Format.numPr.numId := docx.NumberingObject().NumberId('bullet', i); //项目编号 p.Format.numPr.numId := docx.NumberingObject().NumberId('bullet', i); //项目编号
p.Font.Size := 28; p.Font.Size := 14;
p.Font.Color := 'FF0000'; p.Font.Color := 'FF0000';
p.Font.Bold := true; p.Font.Bold := true;
p.Format.LeftIndent := 700;//段落左边距 p.Format.LeftIndent := 700;//段落左边距
@@ -829,7 +831,7 @@ Begin
p.Font.Name := '宋体'; p.Font.Name := '宋体';
p.Font.Color := 'FF0000'; p.Font.Color := 'FF0000';
p.Font.Bold := true; p.Font.Bold := true;
p.Font.Size := 29; p.Font.Size := 15;
p1 := docx.AddParagraph(p, -1, nil); p1 := docx.AddParagraph(p, -1, nil);
println(' >>OK\n'); println(' >>OK\n');
@@ -940,10 +942,10 @@ Function _AddClassHelpTable(docx, data);
Begin Begin
//设置边框属性 //设置边框属性
tbl := docx.CreateTable(data, true, true); tbl := docx.CreateTable(data, true, true);
tbl.Format.Borders.Top.Size := 24; tbl.Format.Borders.Top.Size := 12;
tbl.Format.Borders.Left.Size := 24; tbl.Format.Borders.Left.Size := 12;
tbl.Format.Borders.Bottom.Size := 24; tbl.Format.Borders.Bottom.Size := 12;
tbl.Format.Borders.Right.Size := 24; tbl.Format.Borders.Right.Size := 12;
tbl.Format.Borders.Top.Val := 'thinThickThinMediumGap'; tbl.Format.Borders.Top.Val := 'thinThickThinMediumGap';
tbl.Format.Borders.Left.Val := 'thinThickThinMediumGap'; tbl.Format.Borders.Left.Val := 'thinThickThinMediumGap';
tbl.Format.Borders.Bottom.Val := 'thinThickThinMediumGap'; tbl.Format.Borders.Bottom.Val := 'thinThickThinMediumGap';
@@ -1144,7 +1146,7 @@ Begin
if title then Begin if title then Begin
p.Format.numPr.Level := 0;//项目编号 p.Format.numPr.Level := 0;//项目编号
p.Format.numPr.numId := numId; p.Format.numPr.numId := numId;
p.Font.Size := 28; p.Font.Size := 14;
p.Font.Color := 'FF0000'; p.Font.Color := 'FF0000';
p.Font.Bold := true; p.Font.Bold := true;
p.Format.LeftIndent := 500;//段落左边距 p.Format.LeftIndent := 500;//段落左边距
+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.
+18 -6
View File
@@ -1,4 +1,4 @@
# OfficePlugin # TSOffice
TSOffice 项目:纯 TSL 代码实现 excel、word 文件读写 TSOffice 项目:纯 TSL 代码实现 excel、word 文件读写
@@ -6,24 +6,36 @@ TSOffice 项目:纯 TSL 代码实现 excel、word 文件读写
### windows ### windows
对应文件夹的dll文件按如下要求 对应文件夹的 dll 文件按如下要求
- `fmt_pubkrnl_plugin` 放入 tsl 安装根目录下 Plugin 文件夹
- `office_plugin` 放入 tsl 安装根目录下 Plugin 文件夹 - `office_plugin` 放入 tsl 安装根目录下 Plugin 文件夹
可选:
- `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
File diff suppressed because it is too large Load Diff
+23 -6
View File
@@ -1,4 +1,4 @@
// Version 1.3.0 // Version 1.5.0
Type TSExcelFile = Class Type TSExcelFile = Class
///Version: V1.0 2022-08-08 ///Version: V1.0 2022-08-08
@@ -18,7 +18,17 @@ Type TSExcelFile = Class
Function Create(alias, fname); overload; Function Create(alias, fname); overload;
Begin Begin
init(); init();
OpenFile(alias, fname); OpenFile(alias, fname, nil);
End;
///构造函数,打开已经存在的excel文件
///alias: string,文件目录别名
///fname: string,文件名
///passwd: string,密码
Function Create(alias, fname, passwd); overload;
Begin
init();
OpenFile(alias, fname, passwd);
End; End;
//析构函数 //析构函数
@@ -35,12 +45,13 @@ Type TSExcelFile = Class
///打开excel文件 ///打开excel文件
///alias: string,文件目录别名 ///alias: string,文件目录别名
///fname: string,文件名 ///fname: string,文件名
///[passwd]: string,密码
///返回: [err, errmsg] ///返回: [err, errmsg]
Function OpenFile(alias, fname); Function OpenFile(alias, fname, passwd);
Begin Begin
init();
if not ifObj(zipfile_) then return array(-1, 'Create ZipFile object fail.'); if not ifObj(zipfile_) then return array(-1, 'Create ZipFile object fail.');
[err, errmsg] := zipfile_.Open(alias, fname); if zipfile_.FilesCount() > 0 then zipfile_ := new ZipFile();
[err, errmsg] := zipfile_.Open(alias, fname, passwd);
if err=0 then Begin if err=0 then Begin
workbook_ := new xlsxWorkBook(zipfile_); workbook_ := new xlsxWorkBook(zipfile_);
workbook_.Load(); workbook_.Load();
@@ -69,6 +80,12 @@ Type TSExcelFile = Class
return zipfile_.Save(); return zipfile_.Save();
End; End;
///设置密码
Function SetPassword(passwd)
Begin
zipfile_.Password := passwd;
End;
///打开二进制内容 ///打开二进制内容
///data: 二进制数据 ///data: 二进制数据
///返回: [err, errmsg] ///返回: [err, errmsg]
@@ -898,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));
+299 -276
View File
@@ -1,276 +1,299 @@
Type NodeInfo = class Type NodeInfo = class
public public
Function Create(p, name); Function Create(parentObj, name);
Begin Begin
if ifObj(p) then if ifObj(parentObj) then
NodeUri := p.NodeUri = '' ? name : (p.NodeUri + '/' + name); NodeUri := parentObj.NodeUri = '' ? name : (parentObj.NodeUri + '/' + name);
else else
NodeUri := ''; NodeUri := '';
NodeName := name; NodeName := name;
ExtAttr := array(); ExtAttr := array();
ExtNodes := array(); ExtNodes := array();
ReplaceArr := array(); ReplaceArr := array();
End End
Function Root(); virtual; Function Root(); virtual;
Begin Begin
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;
Begin Function Delete();overload;
End Begin
if ifObj(RootObj) then
Function GetAttrs(); virtual; begin
Begin curNode := class(TSXml).GetNode(RootObj, NodeUri);
return ExtAttr; if ifObj(curNode) then curNode.DeleteChildren();
End end
End;
Function GetChildren(); virtual;
Begin Function Delete(name);overload;
return ExtNodes; Begin
End if not ifObj(RootObj) then return false;
node := NodeUri <> '' ? class(TSXml).GetNode(RootObj, NodeUri) : RootObj;
Function GetNode(index); // 返回的index的对象
Begin attrs := GetAttrsEx();
return ExtNodes[index]['obj']; lName := lowerCase(name);
End r := sselect * from attrs where lName = lowerCase([0]) end;
if istable(r) then
Function GetCount(); // 返回当前节点的个数 begin
Begin node.DeleteAttribute(r[1]);
return length(ExtAttr); return true;
End end
// arr := array(('Size', 'sz', 15), ('Style', 'style', 'line')); children := GetChildren();
Function AddAttr(arr); // 添加属性 r := select * from children where lName = lowerCase(['field']) end;
Begin if istable(r) then Begin
if not istable(arr) then return; r := r[0];
ExtAttr union= arr; delete_node := node.FirstChildElement(r['name']);
return 1; if ifObj(delete_node) then
End begin
node.DeleteChild(delete_node);
Function Marshal(); return true;
Begin end
children_ := nil; End;
GetChildrenEx(); //优化为变量,减少数据COPY2022-12-10 return false;
child_arr := array(); End;
len := 0;
for i:=0 to length(children_)-1 do Function GetAttrs(); virtual;
begin Begin
node_type := children_[i]['nodeType']; return ExtAttr;
obj := children_[i]['obj']; End
if ifnil(obj) then continue;
//find := select thisrowindex as "rowindex_", * from child_arr where ['name'] = children_[i]['name'] end; //优化为循环,性能提高15-20%2022-12-20 Function GetChildren(); virtual;
find := array(); Begin
for j:=length(child_arr)-1 downto 0 do Begin //支持列表模式(如多节点:<w:t xml:space=""></w:t>),查找最近的节点 return ExtNodes;
if child_arr[j]['name'] = children_[i]['name'] then Begin End
find[0] := child_arr[j];
find[0]['rowindex_'] := j; Function GetNode(index); // 返回的index的对象
break; Begin
End; return ExtNodes[index]['obj'];
End; End
if not ifnil(obj) and not ifObj(obj) and istable(find) and ifstring(children_[i]['attrEx']) and children_[i]['attrEx'] <> '' then
begin Function GetCount(); // 返回当前节点的个数
if not ifarray(find[0]['attributes']) then find[0]['attributes'] := array(); Begin
key := children_[i]['attrEx']; return length(ExtAttr);
find[0]['attributes'] union= array(key : obj); End
child_arr[find[0]['rowindex_']]['attributes'] := find[0]['attributes'];
continue; // arr := array(('Size', 'sz', 15), ('Style', 'style', 'line'));
end Function AddAttr(arr); // 添加属性
Begin
arr := array('type': 'element', 'name': children_[i]['name'], 'attributes': array()); if not istable(arr) then return;
if node_type = 'empty' then // <b/> ExtAttr union= arr;
begin return 1;
if obj = 0 then arr['attributes'] := array('val': 0); End
else if obj = 1 then arr['attributes'] := array('val': 1)
end Function Marshal();
else if node_type = 'pcdata' then Begin
begin children_ := nil;
arr['children'] := array(('type': 'pcdata', 'value': obj)); GetChildrenEx(); //优化为变量,减少数据COPY2022-12-10
end child_arr := array();
else if ifObj(obj) then name_map := array();
begin len := 0;
marshal := obj.Marshal(); for i:=0 to length(children_)-1 do
if length(marshal['children'])=0 and length(marshal['attributes'])=0 then continue; begin
arr['children'] := marshal['children']; node_type := children_[i]['nodeType'];
arr['attributes'] union= marshal['attributes']; obj := children_[i]['obj'];
end if ifnil(obj) then continue;
else if not ifObj(obj) and not ifnil(name_map[children_[i]['name']]) and children_[i]['attrEx'] <> '' then
begin begin
key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; child_arr[name_map[children_[i]['name']]]['attributes'] union=array(children_[i]['attrEx'] : obj);
arr['attributes'] := array(key : obj); continue;
end end
child_arr[len++] := arr; arr := array('type': 'element', 'name': children_[i]['name'], 'attributes': array());
end if node_type = 'empty' then // <b/>
begin
name_arr := str2array(NodeName, '/'); empty_name := children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val';
tmp_arr := array('type': 'element', 'name': name_arr[length(name_arr)-1], 'children': child_arr); if obj = 0 then arr['attributes'] := array(empty_name: 0);
for i:=length(name_arr)-2 downto 0 do else if obj = 1 then arr['attributes'] := array(empty_name: 1);
begin end
tmp_arr := array('type': 'element', 'name': name_arr[i], 'children': array(tmp_arr)); else if node_type = 'pcdata' then
end begin
arr['children'] := array(('type': 'pcdata', 'value': obj));
attrs_arr := GetAttrs(); end
tmp_arr['attributes'] := array(); else if ifObj(obj) then
for i:=0 to length(attrs_arr)-1 do begin
begin marshal := obj.Marshal();
if not ifnil(attrs_arr[i, 2]) then Begin if length(marshal['children'])=0 and length(marshal['attributes'])=0 then continue;
tmp_arr['attributes'][ attrs_arr[i, 1] ] := attrs_arr[i, 2]; arr['children'] := marshal['children'];
End; arr['attributes'] union= marshal['attributes'];
end end
return tmp_arr; else
End begin
key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val';
Function NewChildNode(nodeArr); arr['attributes'] := array(key : obj);
Begin end
if not ifarray(nodeArr) then return 0; name_map[children_[i]['name']] := len;
if not ifstring(nodeArr['name']) then return 0; child_arr[len++] := arr;
arr := array(( end
'name': nodeArr['name'],
'obj': nodeArr['obj'], name_arr := str2array(NodeName, '/');
'attrEx': nodeArr['attrEx'], tmp_arr := array('type': 'element', 'name': name_arr[length(name_arr)-1], 'children': child_arr);
'nodeType': nodeArr['nodeType'], for i:=length(name_arr)-2 downto 0 do
)); begin
ExtNodes union= arr; tmp_arr := array('type': 'element', 'name': name_arr[i], 'children': array(tmp_arr));
return 1; end
End
attrs_arr := GetAttrs();
Function Value(name); tmp_arr['attributes'] := array();
Begin for i:=0 to length(attrs_arr)-1 do
if not ifObj(RootObj) then return nil; begin
if NodeUri <> '' then if not ifnil(attrs_arr[i, 2]) then Begin
node := class(TSXml).GetNode(RootObj, NodeUri); tmp_arr['attributes'][ attrs_arr[i, 1] ] := attrs_arr[i, 2];
else End;
node := RootObj; end
if not ifObj(node) then return nil; return tmp_arr;
End
attrs := GetAttrsEx();
lName := lowerCase(name); Function NewChildNode(nodeArr);
r := sselect * from attrs where lName = lowerCase([0]) end; Begin
if istable(r) then if not ifarray(nodeArr) then return 0;
begin if not ifstring(nodeArr['name']) then return 0;
value := node.GetAttribute(r[1]); arr := array((
return trystrtofloat(value, r) ? r : value; 'name': nodeArr['name'],
end 'obj': nodeArr['obj'],
'attrEx': nodeArr['attrEx'],
children := GetChildren(); 'nodeType': nodeArr['nodeType'],
r := select * from children where lName = lowerCase(['field']) end; ));
if istable(r) then Begin ExtNodes union= arr;
r := r[0]; return 1;
node := node.FirstChildElement(r['name']); End
if not ifObj(node) and r['nodeType'] = 'empty' then return false;
if not ifObj(node) then return nil; Function Value(name, nottransferable);
if r['nodeType'] = 'pcdata' then //返回文本串 Begin
return node.GetText(); if not ifObj(RootObj) then return nil;
if ifObj(r['obj']) then //对象,返回XML串 if NodeUri <> '' then
return node.Data(); node := class(TSXml).GetNode(RootObj, NodeUri);
key := r['attrName'] ? r['attrName'] : r['attrEx'] ? r['attrEx'] : 'val'; else
value := node.GetAttribute(key); node := RootObj;
if r['nodeType'] = 'empty' and value = '' then return true; if not ifObj(node) then return nil;
return trystrtofloat(value, r) ? r : value;
End; attrs := GetAttrsEx();
return nil; lName := lowerCase(name);
End; r := sselect * from attrs where lName = lowerCase([0]) end;
if istable(r) then
Function Replace(hash, bChild); begin
Begin value := node.GetAttribute(r[1]);
if istable(hash) then Begin return nottransferable ? value : trystrtofloat(value, r) ? r : value;
ReplaceArr := hash; end
replaceNodeName();
if bChild then Begin children := GetChildren();
r := GetChildren(); r := select * from children where lName = lowerCase(['field']) end;
for i:=0 to length(r)-1 do Begin if istable(r) then Begin
if ifObj(r[i]['obj']) then r := r[0];
r[i]['obj'].Replace(hash, bChild); node := node.FirstChildElement(r['name']);
End; if not ifObj(node) and r['nodeType'] = 'empty' and not nottransferable then return false;
End; if not ifObj(node) then return nil;
End; if r['nodeType'] = 'pcdata' then //返回文本串
End return node.GetText();
if ifObj(r['obj']) then //对象,返回XML串
Function GetChildrenEx(); return node.Data();
Begin key := r['attrName'] ? r['attrName'] : r['attrEx'] ? r['attrEx'] : 'val';
if not ifarray(children_) then Begin value := node.GetAttribute(key);
children_ := getChildren(); if r['nodeType'] = 'empty' and value = '' then return true;
if not istable(ReplaceArr) then Begin return nottransferable ? value : trystrtofloat(value, r) ? r : value;
for i:=0 to length(children_)-1 do Begin End;
if ifarray(children_[i]['obj']) then Begin return nil;
if istable(children_[i]['obj']) then End;
hasArr := 1;
else Function Replace(hash, bChild);
children_[i]['obj'] := nil; Begin
End; if istable(hash) then Begin
End; ReplaceArr := hash;
End; replaceNodeName();
if hasArr or istable(ReplaceArr) then Begin if bChild then Begin
a := array(); r := GetChildren();
for i:=0 to length(children_)-1 do Begin for i:=0 to length(r)-1 do Begin
if istable(ReplaceArr) then if ifObj(r[i]['obj']) then
children_[i]['name'] := ReplaceName(children_[i]['name']); r[i]['obj'].Replace(hash, bChild);
if istable(children_[i]['obj']) then Begin End;
a union= children_[i]['obj']; End;
End End;
else End
a[ length(a) ] := children_[i];
end; Function GetChildrenEx();
children_ := a; Begin
End; if not ifarray(children_) then Begin
End; children_ := getChildren();
End; if not istable(ReplaceArr) then Begin
for i:=0 to length(children_)-1 do Begin
Function GetAttrsEx(); if ifarray(children_[i]['obj']) then Begin
Begin if istable(children_[i]['obj']) then
return GetAttrs();//暂时没有发现需要更新属性前缀的情况 hasArr := 1;
if not istable(ReplaceArr) then return GetAttrs(); else
attr := GetAttrs(); children_[i]['obj'] := nil;
for i:=0 to length(attr)-1 do End;
attr[i][1] := ReplaceName(attr[i][1]); End;
return attr; End;
End if hasArr or istable(ReplaceArr) then Begin
a := array();
private for i:=0 to length(children_)-1 do Begin
Function replaceNodeName(); if istable(ReplaceArr) then
Begin children_[i]['name'] := ReplaceName(children_[i]['name']);
for k, v in ReplaceArr do if istable(children_[i]['obj']) then Begin
begin a union= children_[i]['obj'];
NodeName := ReplaceStr(NodeName, k, v); End
end else
End a[ length(a) ] := children_[i];
end;
Function ReplaceName(name); children_ := a;
Begin End;
for k,v in ReplaceArr do Begin End;
if k='' then End;
name := v + name;
else Function GetAttrsEx();
name := ReplaceStr(name, k, v); Begin
End; return GetAttrs();//暂时没有发现需要更新属性前缀的情况
return name; if not istable(ReplaceArr) then return GetAttrs();
End; attr := GetAttrs();
public for i:=0 to length(attr)-1 do
NodeName; attr[i][1] := ReplaceName(attr[i][1]);
ExtAttr; return attr;
ExtNodes; End
//Parent;
ReplaceArr; private
RootObj; Function replaceNodeName();
NodeUri:string; Begin
children_; for k, v in ReplaceArr do
End begin
NodeName := ReplaceStr(NodeName, k, v);
end
End
Function ReplaceName(name);
Begin
for k,v in ReplaceArr do Begin
if k='' then
name := v + name;
else
name := ReplaceStr(name, k, v);
End;
return name;
End;
public
NodeName;
ExtAttr;
ExtNodes;
ReplaceArr;
RootObj; // xml node
NodeUri:string;
children_;
End
+27
View File
@@ -178,6 +178,33 @@ Type TOffice = Class
Begin Begin
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
+4
View File
@@ -0,0 +1,4 @@
Function TOfficeInit();
Begin
sysparams['TOffice sys api'] := nil;
End;
+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
+6 -6
View File
@@ -30,16 +30,16 @@ Type TDocxChart = Class(TSChart)
Function GetInnerXml(); Function GetInnerXml();
Begin Begin
ETU := 360045;//1cm单位 ETU := 360045;//1cm单位
return fmt('<w:r> return format('<w:r>
<w:drawing> <w:drawing>
<wp:inline> <wp:inline>
<wp:extent cx="{}" cy="{}"/> <wp:extent cx="%d" cy="%d"/>
<wp:effectExtent l="0" t="0" r="19050" b="19050"/> <wp:effectExtent l="0" t="0" r="19050" b="19050"/>
<wp:docPr id="{}" name="{}"/> <wp:docPr id="%d" name="%s"/>
<wp:cNvGraphicFramePr /> <wp:cNvGraphicFramePr />
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"> <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart"> <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart">
<c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId{}"/> <c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId%d"/>
</a:graphicData> </a:graphicData>
</a:graphic> </a:graphic>
</wp:inline> </wp:inline>
@@ -52,8 +52,8 @@ Type TDocxChart = Class(TSChart)
return true; return true;
End; End;
docx_; [weakref]docx_;
chartId_; chartId_;
rId_; rId_;
xmlObj_; xmlObj_;
End; End;
+625
View File
@@ -0,0 +1,625 @@
Type TDocxCopy = class
Function Create(oldObj, newObj)
Begin
old_docx_obj_ := oldObj;
new_docx_obj_ := newObj;
copy_table_ := array();
copy_paragraph_ := array();
copy_drawing_ := array();
style_copy_obj_ := new TDocxStyleCopy(oldObj.StyleObject(), newObj.StyleObject());
number_copy_obj_ := new TDocxNumberCopy(oldObj, newObj);
footnote_copy_obj_ := new TDocxFootnoteCopy(oldObj, newObj);
End;
Function Init();
Begin
style_copy_obj_.Init();
End;
///从posOpt位置开始复制word
///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加图片
Function Copy(posOpt);
Begin
// 复制所有的样式
style_copy_obj_.CopyStyle(number_copy_obj_);
parts := new_docx_obj_.Body().Parts();
pos := old_docx_obj_.GetPosNode(posOpt);
for i:=0 to length(parts)-1 do
begin
case GetPartType(parts[i]) of
0: pos := CopyParagraph(parts[i], pos);
1: pos := CopyDrawing(parts[i], pos);
2: pos := CopyTable(parts[i], pos);
end;
end
End;
Function CopyParagraph(obj, pos);
Begin
paragraph := old_docx_obj_.Body().CopyWp(obj, pos);
SetParagraphInfo(paragraph);
copy_paragraph_[length(copy_paragraph_)] := paragraph;
return paragraph;
End;
Function CopyDrawing(obj, pos);
Begin
paragraph := old_docx_obj_.Body().CopyWp(obj, pos);
SetDrawingInfo(paragraph);
copy_drawing_[length(copy_drawing_)] := paragraph;
return paragraph;
End;
Function CopyTable(obj, pos);
Begin
table := old_docx_obj_.Body().CopyWtbl(obj, pos);
SetTableInfo(table);
copy_table_[length(copy_table_)] := table;
return table;
End;
Function GetCopiedTable();
Begin
return copy_table_;
End;
Function GetCopiedParagraph();
Begin
return copy_paragraph_;
End;
Function GetCopiedDrawing();
Begin
return copy_drawing_;
End;
private
Function DeleteComment(paragraph);
Begin
node := paragraph.node_.FirstChildElement('w:commentRangeStart');
while ifObj(node) do
begin
name := node.GetName();
if name = "w:commentRangeStart" or name = "w:commentRangeEnd" then
begin
delete_node := node;
node := node.NextElement();
paragraph.node_.DeleteChild(delete_node);
if node.FirstChildElement('w:commentReference') then
begin
delete_node := node;
node := node.NextElement();
paragraph.node_.DeleteChild(delete_node);
end
end
else begin
node := node.NextElement();
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);
Begin
// 获取新文件的图片
rembed := node.GetAttribute('r:embed');
rels := new_docx_obj_.Zip().Get('word/_rels/document.xml.rels');
target := class(TSXml).FindRelationshipTarget(rels, rembed);
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/media/image', ['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 := "media/image" $ image_cnt $ '.' $ postfix;
[rid, tar] := class(TSXml).FindRelationshipRid(xml, '');
rid ++;
class(TSXml).AddRelationshipRid(xml, image_path, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', 'rId' $ rid);
zip.Add('word/' + image_path, image_file);
contentXml := zip.Get('[Content_Types].xml');
class(TSXml).AddDefaultContentType(contentXml, postfix, 'image/' $ postfix);
end
end
node.SetAttribute('r:embed', 'rId' $ rid);
End;
Function SetChart(node);
Begin
rid := node.GetAttribute('r:id');
rels := new_docx_obj_.Zip().Get('word/_rels/document.xml.rels');
target := class(TSXml).FindRelationshipTarget(rels, rid);
new_zip := new_docx_obj_.Zip();
chart_file := new_zip.Get('word/' $ target);
// 复制charN.xml
zip := old_docx_obj_.Zip();
files := sselect ['FileName'] from zip.Files() where AnsiStartsText('word/charts/chart', ['FileName']) end;
new_chart_file := "charts/chart" $ (length(files) + 1) $ ".xml";
xml := zip.Get('word/_rels/document.xml.rels');
[new_rid, tar] := class(TSXml).FindRelationshipRid(xml, '');
new_rid++;
class(TSXml).AddRelationshipRid(xml, new_chart_file, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", 'rId' $ new_rid);
zip.Add('word/' + new_chart_file, chart_file.Data());
contentXml := zip.Get('[Content_Types].xml');
class(TSXml).AddOverrideContentType(contentXml, '/word/' + new_chart_file, 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml');
node.SetAttribute('r:id', 'rId' $ new_rid);
// 复制charN.xml.rels
chart_rels := "word/charts/_rels" + target[pos('/', target):] $ ".rels";
chart_rels_xml := new_zip.Get(chart_rels);
if ifObj(chart_rels_xml) then
begin
zip.Add('word/charts/_rels/chart' $ (length(files) + 1) $ ".xml.rels", chart_rels_xml.Data());
relationship := chart_rels_xml.FirstChildElement('Relationships').FirstChildElement('Relationship');
while ifObj(relationship) do
begin
target := relationship.GetAttribute('Target');
target_path := AnsiReplaceText(target, '..', 'word');
file := new_zip.Get(target_path);
if ifObj(file) then
begin
[new_file, filetype] := GetNewTargetFileName(zip, target_path);
zip.Add(new_file, file.Data());
if filetype then Class(TSXml).AddDefaultContentType(contentXml, filetype[2:], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
end
relationship := relationship.NextElement();
end;
end
End;
Function GetNewTargetFileName(zip, fileName);
Begin
files := zip.Files()[:, 'FileName'];
ret := ParseRegExpr("(.*/)(\\w+)(\.\\w+)$", fileName, "", result, Mpos, Mlen);
count := 0;
while fileName in files do
begin
if ret then
fileName := result[0][1] $ result[0][2] $ "tinysoft" $ count $ result[0][3];
else fileName := fileName $ "tinysoft" $ count;
count++;
end
if ret then filetype := result[0][3];
return array(fileName, filetype);
End;
Function SetDrawingInfo(drawing);
Begin
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
begin
node := class(TSXml).GetNode(graphic_node,'pic:pic/pic:blipFill/a:blip');
if ifObj(node) then SetPic(node);
node := class(TSXml).GetNode(graphic_node, 'c:chart');
if ifObj(node) then SetChart(node);
end;
End;
Function SetParagraphInfo(paragraph);
Begin
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
begin
styleid := style.GetAttribute('w:val');
new_id := style_copy_obj_.GetStyleNewId(styleid);
if new_id then style.SetAttribute('w:val', new_id);
end
End;
Function CopyNumber(node, path);
Begin
numpr := class(TSXml).GetNode(node, path);
if ifObj(numpr) then
begin
id := numpr.GetAttribute('w:val');
numberid := number_copy_obj_.CopyNumbering(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;
Function SetTableInfo(table);
Begin
style := class(TSXml).GetNode(table.node_, 'w:tblPr/w:tblStyle');
if ifObj(style) then
begin
id := style.GetAttribute('w:val');
new_id := style_copy_obj_.GetStyleNewId(id);
if new_id then style.SetAttribute('w:val', new_id);
end
col := table.Cols();
row := table.Rows();
for r:=1 to row do
begin
for c:=1 to col do
begin
cell := table.Cell(r, c);
if not cell then continue;
node := cell.node_.FirstChildElement();
while ifObj(node) do
begin
name := node.GetName();
if name = 'w:tbl' then
begin
obj := TOfficeObj('TTable');
obj.Init(node);
SetTableInfo(obj);
end
else if name = "w:p" then
begin
// draw := class(TSXml).GetNode(node, 'w:r/w:drawing');
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
node := node.NextElement();
end
end
end
End;
/// 普通段落: 0
/// 图片段落: 1
/// 表格: 2
/// 其他类型暂不复制
Function GetPartType(part);
Begin
name := part.name_;
case name of
'w:p':
begin
if GetDrawingNode(part.node_) then return 1;
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 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
old_docx_obj_;
new_docx_obj_;
style_copy_obj_;
number_copy_obj_;
footnote_copy_obj_;
copy_table_;
copy_paragraph_;
copy_drawing_;
End;
Type TDocxStyleCopy = class
Function Create(oldObj, newObj);
Begin
old_style_obj_ := oldObj;
new_style_obj_ := newObj;
style_id_map_ := array();
style_name_map_ := array();
style_id_map2_ := array();
style_name_map2_ := array();
id_map_ := array();
End;
Function Init();
Begin
id_styles := new_style_obj_.Styles();
for id, obj in id_styles do
begin
new_obj := obj;
id_map_[id] := new_obj;
SetId(new_obj, id);
SetName(new_obj);
end
End;
Function CopyStyle(numberobj);
Begin
for id, obj in id_map_ do
begin
SetBasedOn(obj);
SetNumId(obj, numberobj);
SetLink(obj);
old_style_obj_.CopyStyle(obj);
end;
End;
Function GetStyleNewId(oldId)
Begin
if ifnumber(oldId) then oldId := tostring(oldId);
return style_id_map_[oldId];
End;
private
Function SetId(obj, id);
Begin
new_id := GetNewId(id);
obj.node_.SetAttribute('w:styleId', new_id);
style_id_map_[id] := new_id;
style_id_map2_[new_id] := id;
End;
Function SetName(obj);
Begin
name_node := obj.node_.FirstChildElement('w:name');
name := name_node.GetAttribute('w:val');
new_name := GetNewName(name);
name_node.SetAttribute('w:val', new_name);
style_name_map_[name] := new_name;
style_name_map2_[new_name] := name;
End;
Function SetBasedOn(obj);
Begin
basedon := obj.node_.FirstChildElement('w:basedOn');
if ifObj(basedon) then
begin
val := basedon.GetAttribute('w:val');
if style_id_map_[val] then basedOn.SetAttribute('w:val', style_id_map_[val]);
end
End;
Function SetLink(obj);
Begin
link := obj.node_.FirstChildElement('w:link');
if ifObj(link) then
begin
val := link.GetAttribute('w:val');
if style_id_map_[val] then link.SetAttribute('w:val', style_id_map_[val]);
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);
Begin
new_name := name;
while ifObj(old_style_obj_.GetStyle(class(TSXml).Utf8ToCurCodePage(new_name))) or style_name_map2_[new_name] do
new_name := new_name $ crc32(inttostr(random(2000000)));
return new_name;
End;
Function GetNewId(id);
Begin
new_id := id;
while ifObj(old_style_obj_.GetStyleById(new_id)) or style_id_map2_[new_id] do
new_id := new_id $ crc32(inttostr(random(2000000)));
return new_id;
End;
private
old_style_obj_;
new_style_obj_;
style_id_map_; // [old_id: new_id];
style_name_map_; // [old_name: new_name];
style_id_map2_; // [new_id: old_id];
style_name_map2_; // [old_name: new_name];
id_map_; // [id: styleobj]
End;
Type TDocxNumberCopy = class
Function Create(oldObj, newObj);
Begin
numberingxml := newObj.Zip().Get('word/numbering.xml');
if ifObj(numberingxml) then
begin
old_number_obj_ := oldObj.NumberingObject();
new_number_obj_ := newObj.NumberingObject();
end
else begin
old_number_obj_ := nil;
new_number_obj_ := nil;
end
id_map_ := array();
End;
Function CopyNumbering(number);
Begin
if ifObj(old_number_obj_) and ifObj(new_number_obj_) then
begin
if (obj := new_number_obj_.NumberStyle(number)) and not id_map_[number] then
begin
number_obj := old_number_obj_.CopyNumber(obj);
id_map_[number] := number_obj;
end
return id_map_[number];
end
End;
private
old_number_obj_;
new_number_obj_;
id_map_; // [id: styleobj]
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;
+207 -188
View File
@@ -1,188 +1,207 @@
Type TDocxStyles = Class Type TDocxStyles = Class
//段落格式 //段落格式
Function Create(docx); Function Create(docx);
Begin Begin
docx_ := docx; docx_ := docx;
stylesXml_ := docx.Zip().Get('word/styles.xml'); stylesXml_ := docx.Zip().Get('word/styles.xml');
idMap_ := array(); idMap_ := array();
nameMap_ := array(); nameMap_ := array();
maxStyleId_ := 1; maxStyleId_ := 1;
if ifObj(stylesXml_) then Begin if ifObj(stylesXml_) then Begin
stylesNode := stylesXml_.FirstChildElement('w:styles'); stylesNode := stylesXml_.FirstChildElement('w:styles');
if ifObj(stylesNode) then Begin if ifObj(stylesNode) then Begin
node := stylesNode.FirstChildElement('w:style'); node := stylesNode.FirstChildElement('w:style');
while ifObj(node) do Begin while ifObj(node) do Begin
o := TOfficeObj('TDocxStyle'); o := TOfficeObj('TDocxStyle');
o.Init(node); o.Init(node);
id := StrToIntDef(o.StyleId, 0); id := StrToIntDef(o.StyleId, 0);
if id > 0 and maxStyleId_ <= id then if id > 0 and maxStyleId_ <= id then
maxStyleId_ := id + 1; maxStyleId_ := id + 1;
_addStyle(o); _addStyle(o);
node := node.NextElement('w:style'); node := node.NextElement('w:style');
End; End;
pNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:pPrDefault'); pNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:pPrDefault');
if ifObj(pNode) then if ifObj(pNode) then
defaultPpr_ := Class(TSXml).ReadPprFormat(pNode); defaultPpr_ := Class(TSXml).ReadPprFormat(pNode);
rNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:rPrDefault'); rNode := class(TSXml).GetNode(stylesNode, 'w:docDefaults/w:rPrDefault');
if ifObj(rNode) then if ifObj(rNode) then
defaultRpr_ := Class(TSXml).ReadRprFormat(rNode); defaultRpr_ := Class(TSXml).ReadRprFormat(rNode);
End; End;
End; End;
End; End;
///缺省样式 ///缺省样式
///styleType:样式类型(paragraph、character、table ///styleType:样式类型(paragraph、character、table
///返回:TDocxStyle对象 ///返回:TDocxStyle对象
Function Default(styleType); Function Default(styleType);
Begin Begin
for k, obj in idMap_ do Begin for k, obj in idMap_ do Begin
if obj.wType = styleType then Begin if obj.wType = styleType then Begin
v := obj.node_.GetAttribute('w:default'); v := obj.node_.GetAttribute('w:default');
if v <> '1' then if v <> '1' then
return obj; return obj;
End; End;
End End
return nil; return nil;
End; End;
///返回指定名称的TDocxStyle ///返回指定名称的TDocxStyle
///name:样式名称 ///name:样式名称
///返回:TDocxStyle对象 ///返回:TDocxStyle对象
Function GetStyle(name); Function GetStyle(name);
Begin Begin
return nameMap_[ lowercase(name) ]; return nameMap_[ class(TSXml).CurCodePageToUtf8(lowercase(name)) ];
End; End;
///返回指定StyleId名称的TDocxStyle ///返回指定StyleId名称的TDocxStyle
///idStyleID号(数字ID号或名称字符串) ///idStyleID号(数字ID号或名称字符串)
///返回:TDocxStyle对象 ///返回:TDocxStyle对象
Function GetStyleById(id); Function GetStyleById(id);
Begin Begin
return idMap_[ id ]; newid := ifnumber(id) ? tostring(id) : id;
End; return idMap_[ newid ];
End;
//返回全部LatentStyles对象列表
//返回TDocxStyle对象列表 //返回全部LatentStyles对象列表
Function LatentStyles(); //返回:TDocxStyle对象列表
Begin Function LatentStyles();
r := array(); Begin
node := stylesXml_.FirstChildElement('w:styles'); r := array();
if ifObj(node) then node := stylesXml_.FirstChildElement('w:styles');
node := node.FirstChildElement('w:latentStyles'); if ifObj(node) then
if ifObj(node) then Begin node := node.FirstChildElement('w:latentStyles');
node := node.FirstChildElement('w:lsdException'); if ifObj(node) then Begin
while ifObj(node) do Begin node := node.FirstChildElement('w:lsdException');
o := TOfficeObj('TDocxStyle'); while ifObj(node) do Begin
o.Init(node); o := TOfficeObj('TDocxStyle');
r[ length(r) ] := o; o.Init(node);
node := node.NextElement('w:lsdException'); r[ length(r) ] := o;
End; node := node.NextElement('w:lsdException');
End; End;
return r; End;
End; return r;
End;
///返回全部Styles对象列表
///返回TDocxStyle对象列表 ///返回全部Styles对象列表
Function Styles(); ///返回:TDocxStyle对象列表
Begin Function Styles();
return idMap_; Begin
End; return idMap_;
End;
///插入新的段落样式
///styleId:样式ID,可以是自定义名称 ///插入新的段落样式
///xmlStrInnerXml串 ///styleId:样式ID,可以是自定义名称
///返回:TDocxStyle对象 ///xmlStrInnerXml串
Function AddStyleByInnerXml(styleId, xmlStr); ///返回:TDocxStyle对象
Begin Function AddStyleByInnerXml(styleId, xmlStr);
if ifstring(styleId) and styleId <> '' then Begin Begin
style := GetStyle(styleId); if ifstring(styleId) and styleId <> '' then Begin
if ifObj(style) then style := GetStyle(styleId);
return style; if ifObj(style) then
node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr); return style;
node.SetAttribute('w:styleId', styleId); node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr);
End node.SetAttribute('w:styleId', styleId);
else Begin End
node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr); else Begin
node.SetAttribute('w:styleId', maxStyleId_++); node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(xmlStr);
End; node.SetAttribute('w:styleId', maxStyleId_++);
o := TOfficeObj('TDocxStyle'); End;
o.Init(node); o := TOfficeObj('TDocxStyle');
_addStyle(o); o.Init(node);
return o; _addStyle(o);
End; return o;
End;
///插入新的段落样式
///oTDocxStyle对象 ///插入新的段落样式
///StyleId:样式ID,可以是自定义名称 ///oTDocxStyle对象
///返回:TDocxStyle对象 ///StyleId:样式ID,可以是自定义名称
Function AddStyle(o, StyleId); ///返回:TDocxStyle对象
Begin Function AddStyle(o, StyleId);
if ifObj(o) then Begin Begin
if ifString(StyleId) and StyleId <> '' and not ifObj(idMap_[ StyleId ]) then if ifObj(o) then Begin
o.StyleId := StyleId; if ifString(StyleId) and StyleId <> '' and not ifObj(idMap_[ StyleId ]) then
else o.StyleId := StyleId;
o.StyleId := maxStyleId_++; else
node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(o.Marshal()); o.StyleId := maxStyleId_++;
obj := TOfficeObj('TDocxStyle'); node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(o.Marshal());
obj.Init(node); obj := TOfficeObj('TDocxStyle');
_addStyle(obj); obj.Init(node);
return obj; _addStyle(obj);
End; return obj;
return nil; End;
End; return nil;
End;
///插入新的LatentStyle段落样式
///oTDocxStyle对象 ///复制样式
///返回:TDocxStyle对象 ///newstyle:样式节点TDocxStyle对象
Function AddLatentStyle(o); ///返回:TDocxStyle对象
Begin Function CopyStyle(newstyle);
if ifObj(o) then Begin Begin
latentStyles := stylesXml_.FirstChildElement('w:styles').InsertEndChild('w:latentStyles'); if ifObj(newstyle) and ifObj(newstyle.node_) then Begin
node := latentStyles.InsertEndChild('lsdException'); node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(newstyle.node_.Marshal()[0]);
node.UnMarshal(o); node.DeleteAttribute('w:default');
latentStyles.SetAttribute('w:count', length(LatentStyles())); obj := TOfficeObj('TDocxStyle');
return node; obj.StyleId := node.GetAttribute('w:styleId');
End; obj.Name := node.FirstChildElement('w:name').GetAttribute('w:val');
return nil; obj.Init(node);
End; _addStyle(obj);
return obj;
///插入缺省的段落样式(Title、Heading1-9 End;
///返回:TDocxStyle对象 return nil;
Function AddDefaultStyle(Name); End;
Begin
styleId := AnsiReplaceText(Name, ' ', ''); ///插入新的LatentStyle段落样式
charId := StyleId + 'Char'; ///oTDocxStyle对象
styleFname := 'wStyle/' + styleId + '.xml'; ///返回:TDocxStyle对象
cStyleFname := 'wStyle/' + charId + '.xml'; Function AddLatentStyle(o);
xmlData := TOfficeTemplate(styleFname); Begin
if ifnil(xmlData) then if ifObj(o) then Begin
return xmlData; latentStyles := stylesXml_.FirstChildElement('w:styles').InsertEndChild('w:latentStyles');
o := AddStyleByInnerXml(styleId, xmlData); node := latentStyles.InsertEndChild('lsdException');
node.UnMarshal(o);
charStyle := idMap_[charId]; latentStyles.SetAttribute('w:count', length(LatentStyles()));
if not ifObj(charStyle) then Begin return node;
xmlData := TOfficeTemplate(cStyleFname); End;
if ifstring(xmlData) then Begin return nil;
AddStyleByInnerXml(charId, xmlData); End;
End;
End; ///插入缺省的段落样式(Title、Heading1-9
return o; ///返回:TDocxStyle对象
End; Function AddDefaultStyle(Name);
Begin
Function _addStyle(o); styleId := AnsiReplaceText(Name, ' ', '');
Begin charId := StyleId + 'Char';
idMap_[ o.StyleId ] := o; styleFname := 'wStyle/' + styleId + '.xml';
nameMap_[ lowercase(o.Name) ] := o; cStyleFname := 'wStyle/' + charId + '.xml';
End; xmlData := TOfficeTemplate(styleFname);
if ifnil(xmlData) then
defaultPpr_; return xmlData;
defaultRpr_; o := AddStyleByInnerXml(styleId, xmlData);
private
docx_; charStyle := idMap_[charId];
stylesXml_; if not ifObj(charStyle) then Begin
idMap_; xmlData := TOfficeTemplate(cStyleFname);
nameMap_; if ifstring(xmlData) then Begin
maxStyleId_:integer; AddStyleByInnerXml(charId, xmlData);
End; End;
End;
return o;
End;
Function _addStyle(o);
Begin
idMap_[ o.StyleId ] := o;
nameMap_[ lowercase(o.Name) ] := o;
End;
defaultPpr_;
defaultRpr_;
private
[weakref]docx_;
stylesXml_;
idMap_;
nameMap_;
maxStyleId_:integer;
End;
+23 -4
View File
@@ -76,6 +76,19 @@ Type TNumbering = Class
numIdMap_[''$num.numId] := num.abstractNumId; numIdMap_[''$num.numId] := num.abstractNumId;
return num.numId; return num.numId;
End; End;
///复制number样式
///numberObj: 样式xmlNode
Function CopyNumber(numberObj);
Begin
obj := AddStyle(numberObj, true);
num := TOfficeObj('TNumber');
num.numId := maxNumId_++;
num.abstractNumId := obj.Id;
numberingXml_.FirstChildElement('w:numbering').InsertEndChild(num.Marshal());
numIdMap_[''$num.numId] := num.abstractNumId;
return num.numId;
End;
///根据numId获取TNumStyle对象(已存在) ///根据numId获取TNumStyle对象(已存在)
///返回:TNumStyle对象 ///返回:TNumStyle对象
@@ -148,14 +161,20 @@ Type TNumbering = Class
///新添加项目样式 ///新添加项目样式
///oTNumStyle对象 ///oTNumStyle对象
///返回:TNumStyle对象 ///返回:TNumStyle对象
Function AddStyle(o); Function AddStyle(o, flag);
Begin Begin
if ifObj(o) then Begin if ifObj(o) then Begin
o.abstractNumId := maxAbstractNumId_++; o.abstractNumId := maxAbstractNumId_++;
if flag then
begin
o.node_.SetAttribute('w:abstractNumId', o.abstractNumId);
marshal := o.node_.Marshal()[0];
end
else marshal := o.Marshal();
if ifObj(lastAbstractNumStyle_) then if ifObj(lastAbstractNumStyle_) then
node := numberingXml_.FirstChildElement('w:numbering').InsertAfterChild(lastAbstractNumStyle_, o.Marshal()); node := numberingXml_.FirstChildElement('w:numbering').InsertAfterChild(lastAbstractNumStyle_, marshal);
else else
node := numberingXml_.FirstChildElement('w:numbering').InsertFirstChild(o.Marshal()); node := numberingXml_.FirstChildElement('w:numbering').InsertFirstChild(marshal);
lastAbstractNumStyle_ := node; lastAbstractNumStyle_ := node;
o := TOfficeObj('TNumStyle'); o := TOfficeObj('TNumStyle');
o.Init(node); o.Init(node);
@@ -209,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;
+1 -1
View File
@@ -30,7 +30,7 @@ Type TSTag = Class
Begin Begin
if not ifArray(map_) then Begin if not ifArray(map_) then Begin
map_ := array(); map_ := array();
println('attribute={}',attribute_); //println('attribute={}',attribute_);
arr := Str2Array(attribute_, ' '); arr := Str2Array(attribute_, ' ');
for i := 0 to length(arr)-1 do Begin for i := 0 to length(arr)-1 do Begin
kv := Str2Array(arr[i], '='); kv := Str2Array(arr[i], '=');
@@ -0,0 +1,297 @@
Unit TSWordTemplateMethods;
Interface
Function ExcelChartCopyPic(excelFileName, excelSheetName, chartName, width, height);
Function WordAddOleObjectFromFile(fileName, width, height);
Function WordBr();
Function WordCopyFromExcel(excelFileName, excelSheetName, startRow, startCol, endRow, endCol);
Function WordGetCurrentDocument();
Function WordGetCurrentRange();
Function WordGetFont(prop, value);
Function WordGetLastRange();
Function WordGetLastShape();
Function WordGetLastTable();
Function WordGetLastTableCellProp(row, col, name, value);
Function WordGetLastTableProp(name, value);
Function WordLastTableMerge(row1, col1, row2, col2);
Function WordSetCurrentRange(range);
Function WordSetFont(prop, value);
Function WordSetLastTableCellProp(row, col, name, value);
Function WordSetLastTableProp(name, value);
Function WordSetRangeProp(name, value);
Function WordTemplate(data, template, fileName);
Function WordWrite();
Function WordWritePicFromFile(fileName);
Function WordWriteTable(table, writeIntIndex, writeIntTitle, incIntIndex);
Implementation
Function ExcelChartCopyPic(excelFileName, excelSheetName, chartName, width, height);
Begin
docx := TOfficeApi().GetDocument();
chart := docx.CopyExcelChart(excelFileName, excelSheetName, chartName, width, height, TOfficeApi().GetCurrentPosition());
return ifObj(chart);
End;
Function WordBr();
Begin
TOfficeApi().GetDocument().AddLineBreak(TOfficeApi().Get('CurrentPosition'));
End;
Function WordCopyFromExcel(excelFileName, excelSheetName, startRow, startCol, endRow, endCol);
Begin
excel := new TSXlsFile();
[err, msg] := excel.OpenFile('', excelFileName);
if err then return false;
total_row := excel.TotalRows(excelSheetName);
total_col := excel.TotalCols(excelSheetName);
if not total_row or not total_col then return false;
if ifnil(startRow) then
startRow := 1;
if ifnil(startCol) then
startCol := 1;
if ifnil(endRow) then
endRow := total_row;
if ifnil(endCol) then
endCol := total_col;
data := excel.GetTable(excelSheetName,
CoordinatesToCellName(startCol, startRow),
CoordinatesToCellName(endCol, endRow),
false,
false,
false);
if length(data) = 0 then return false;
//println('data={}',data);
docx := TOfficeApi().GetDocument();
tbl := docx.CreateTable(data, false, false);
tbl.Format.Borders.Top.Val := 'dashed';
tbl.Format.Borders.Left.Val := 'dashed';
tbl.Format.Borders.Bottom.Val := 'dashed';
tbl.Format.Borders.Right.Val := 'dashed';
tbl.Format.Borders.InsideH.Val := 'dashed';
tbl.Format.Borders.InsideV.Val := 'dashed';
tbl := docx.InsertTable(tbl, TOfficeApi().GetCurrentPosition());
End;
Function WordGetCurrentDocument();
Begin
return TOfficeApi().GetDocument();
End;
Function WordGetCurrentRange();
Begin
return TOfficeApi().GetCurrentPosition();
End;
Function WordGetFont(prop, value);
Begin
crun := TOfficeApi().GetCurrentRun();
node := crun.Node().FirstChildElement('w:rPr');
rPr := TOfficeObj('TwrPr');
rPr.InitRootNode(node);
value := rPr.Value(prop);
if not ifnil(value) then return true;
return false;
End;
Function WordGetLastShape();
Begin
node := TOfficeApi().Get('CurrentShape');
if not ifObj(node) then return nil;
uri := 'w:r/w:drawing/wp:inline/a:graphic/a:graphicData/c:chart';
cNode := class(TSXml).GetNode(node, uri);
if ifObj(cNode) then Begin
chart := TOfficeObj('TChart');
chart.Init(TOfficeApi().GetDocument(), node, cNode);
return chart;
End;
pic := TOfficeObj('TPicture');
pic.Init(node);
return pic;
End;
Function WordGetLastRange();
Begin
return TOfficeApi().GetCurrentPosition();
End;
Function WordGetLastTable();
Begin
return TOfficeApi().Get('CurrentTable');
End;
Function WordGetLastTableCellProp(row, col, name, value);
Begin
table_node := TOfficeApi().Get('CurrentTable');
if ifnil(table_node) then return false;
table := TOfficeObj("TTable");
table.Init(table_node);
table_cell := table.Cell(row, col);
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'return table_cell.Format.' $ name_ $ '"' $ value $ '"';
value := eval(&str);
return true;
End;
Function WordGetLastTableProp(name, value);
Begin
table_node := TOfficeApi().Get('CurrentTable');
if ifnil(table_node) then return false;
table := TOfficeObj("TTable");
table.Init(table_node);
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'return table.Format.' $ name_ $ '"' $ value $ '"';
value := eval(&str);
return true;
End;
Function WordLastTableMerge(row1, col1, row2, col2);
Begin
table_node := TOfficeApi().Get('CurrentTable');
if ifnil(table_node) then return false;
table := TOfficeObj("TTable");
table.Init(table_node);
[err1, beg_cell] := CoordinatesToCellName(col1, row1);
[err2, end_cell] := CoordinatesToCellName(col2, row2);
if err1 or err2 then return false;
table.Merge(beg_cell, end_cell, false);
return true;
End;
Function WordSetCurrentRange(range);
Begin
TOfficeApi().Set('CurrentPosition', range);
End;
Function WordSetFont(prop, value);
Begin
run := TOfficeApi().GetCurrentRun();
str := 'run.font.' $ prop $ ' := ' $ '"' $ value $ '"';
eval(&str);
run.Apply();
return true;
End;
Function WordSetLastTableCellProp(row, col, name, value);
Begin
table := TOfficeApi().Get('CurrentTable');
if ifnil(table) then return false;
table_cell := table.Cell(row, col);
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'table_cell.Format.' $ name_ $ ' := ';
if ifstring(value) then
str += '"' $ value $ '"';
else
str := str $ value;
eval(&str);
return true;
End;
Function WordSetLastTableProp(name, value);
Begin
table := TOfficeApi().Get('CurrentTable');
if ifnil(table) then return false;
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'table.Format.' $ name_ $ ' := ';
if ifstring(value) then
str += '"' $ value $ '"';
else
str := str $ value;
eval(&str);
TOfficeApi().Set('CurrentTable', table);
return true;
End;
Function WordSetRangeProp(name, value);
Begin
cur := TOfficeApi().GetCurrentPosition();
if ifnil(cur) then return nil;
End;
Function WordTemplate(data, template, fileName);
Begin
setsysparam('data', data);
docx := new TSDocxFile();
[err, msg] := docx.OpenFile('', template);
if err then return false;
docx.ExecInnerTSL();
if ifstring(fileName) then
begin
[err, msg] := docx.SaveAs('', fileName);
if err then return false;
end
return true;
End;
Function WordWrite();
Begin
docx := TOfficeApi().GetDocument();
curParagraph := TOfficeApi().GetCurrentParagraph();
curRun := TOfficeApi().GetCurrentRun();
for i:=1 to PARAMCOUNT do Begin
argv := params[i];
if ifstring( argv ) then
curRun.AddText( argv );
else if ifnumber(argv) then
curRun.AddText('' $ argv);
else if ifarray(argv) then Begin
tbl := docx.CreateTable(argv, false, false);
tbl := docx.InsertTable(tbl, TOfficeApi().GetCurrentPosition());
End
End
End;
Function WordWritePicFromFile(fileName);
Begin
file_size := fileSize('', fileName);
flag := readfile(rwbinary(), '', fileName, 0, file_size, data);
if not flag then return false;
picture := TOfficeObj('TPicture');
picture.Image := data;
docx := TOfficeApi().GetDocument();
docx.AddPicture(picture, TOfficeApi().GetCurrentPosition());
return true;
End;
Function WordWriteTable(table, writeIntIndex, writeIntTitle, incIntIndex);
Begin
docx := TOfficeApi().GetDocument();
tbl := docx.CreateTable(table, true, writeIntIndex);
table := docx.InsertTable(tbl, TOfficeApi().GetCurrentPosition());
return true;
End;
Function _wordCompTable();
Begin
return array(
'alignment': 'Alignment',
'shadingcolor': 'Shading.Color',
'style': 'StyleID',
'verticalalignment': 'Valign',
'width': 'Width',
);
End;
// TODO:尚未支持
Function WordAddOleObjectFromFile(fileName, width, height);
Begin
End;
Function WordCopyPicFormatExcel(excelFileName, excelSheetName, startRow, startCol, endRow, endCol, picType);
Begin
End;
Function WordGetRangeProp(name, value);
Begin
End;
Function WordLastTableSplit(row, col, rCnt, cCnt);
Begin
End;
End.
+140 -113
View File
@@ -4,7 +4,7 @@ Type TTableContent = class
Begin Begin
Create(docx, nil); Create(docx, nil);
End; End;
Function Create(docx, node);overload; Function Create(docx, node);overload;
Begin Begin
node_ := node; node_ := node;
@@ -15,38 +15,42 @@ Type TTableContent = class
//contentType := docx.Zip().Get('[Content_Types].xml'); //contentType := docx.Zip().Get('[Content_Types].xml');
//class(TSXml).AddOverrideContentType(contentType, 'wmf', 'image/x-wmf'); //class(TSXml).AddOverrideContentType(contentType, 'wmf', 'image/x-wmf');
End; End;
Function SetDefaultFormat(); Function SetDefaultFormat();
Begin Begin
defultFont := impl_.stdPr.rPr; defultFont := impl_.sdtPr.rPr;
defultFont.rFont.cstheme := 'minorBidi'; defultFont.rFont.cstheme := 'minorBidi';
defultFont.rFont.XMLeastAsia := '宋体'; defultFont.rFont.XMLeastAsia := '宋体';
defultFont.rFont.XMLhAnsi := '宋体'; defultFont.rFont.XMLhAnsi := '宋体';
defultFont.rFont.XMLascii := '宋体'; defultFont.rFont.XMLascii := '宋体';
//defultFont.kern := 2; //defultFont.kern := 2;
defultFont.Size := 21; defultFont.Size := 21/2;
defultFont.SzCs := 24; defultFont.SzCs := 24;
defultFont.Lang := 'en-US'; defultFont.Lang := 'en-US';
defultFont.bidi := 'ar-SA'; defultFont.bidi := 'ar-SA';
defultFont.eastAsia := 'zh-CN'; defultFont.eastAsia := 'zh-CN';
defultFont.Color := 'DBDBDB'; defultFont.Color := 'DBDBDB';
defultFormat := impl_.stdPr; defultFormat := impl_.sdtPr;
defultFormat.ID := integer(time()*24*3600); defultFormat.ID := integer(time()*24*3600);
//defultFormat.Color := 'DBDBDB'; //defultFormat.Color := 'DBDBDB';
defultFormat.docPartObj.docPartGallery := 'Table of Contents'; defultFormat.docPartObj.docPartGallery := 'Table of Contents';
defultFormat.docPartObj.docPartUnique := 1; defultFormat.docPartObj.docPartUnique := 1;
//impl_.stdEndPr.rPr.Size := 20; //impl_.sdtEndPr.rPr.Size := 21;
//impl_.stdEndPr.rPr.SzCs := 20; //impl_.sdtEndPr.rPr.SzCs := 22;
impl_.stdEndPr.rPr.Bold := true; impl_.sdtEndPr.rPr.Bold := true;
End; End;
///应用目录样式 ///应用目录样式
Function Apply(); override; Function Apply(); override;
Begin Begin
arr := impl_.Marshal(); // sdtContent 不应该updateNode
tmp_impl := TOfficeObj('TTableContentImpl');
tmp_impl.sdtPr := impl_.sdtPr;
tmp_impl.sdtEndPr := impl_.sdtEndPr;
arr := tmp_impl.Marshal();
class(TSXml).UpdateNode(node_, arr['attributes'], arr['children']); class(TSXml).UpdateNode(node_, arr['attributes'], arr['children']);
End; End;
///添加目录条目 ///添加目录条目
///UpperHeadingLevel:标题最高级别 ///UpperHeadingLevel:标题最高级别
///LowerHeadingLevel:标题最低级别 ///LowerHeadingLevel:标题最低级别
@@ -68,31 +72,43 @@ Type TTableContent = class
mParagraph.pPr.RightIndent := 0; mParagraph.pPr.RightIndent := 0;
mParagraph.pPr.LeftChars := 0; mParagraph.pPr.LeftChars := 0;
mParagraph.pPr.LeftIndent := 0; mParagraph.pPr.LeftIndent := 0;
mParagraph.pPr.StyleID := _GetStyle('TOC');
mParagraph.Run.T := '目录'; mParagraph.Run.T := '目录';
mParagraph.Run.rPr.SetName('宋体', true); mParagraph.Run.rPr.Lang := 'zh-CN';
mParagraph.Run.rPr.Size := 21; //mParagraph.Run.rPr.SetName('宋体', true);
mParagraph.Run.rPr.Bold := true; //mParagraph.Run.rPr.Size := 21/2;
//mParagraph.Run.rPr.Bold := true;
_AddStdContent(mParagraph); _AddStdContent(mParagraph);
goback := TOfficeObj('TParagraph'); goback := TOfficeObj('TParagraph');
id := docx_.Document().GetBookMarkID(); id := docx_.Document().GetBookMarkID();
goback.MarkStart.Name := '_GoBack'; goback.MarkStart.Name := '_GoBack';
goback.MarkStart.ID := id; goback.MarkStart.ID := id;
goback.MarkEnd.ID := id; goback.MarkEnd.ID := id;
_AddStdContent(goback); //_AddStdContent(goback);
//缺省目录,需要word或wps打开后,更新目录 //缺省目录,需要word或wps打开后,更新目录
_AddDefaultTableContent(UpperHeadingLevel, LowerHeadingLevel); //_AddDefaultTableContent(UpperHeadingLevel, LowerHeadingLevel);
//自定义页码计算与word、wps有差异,不推荐使用 //自定义页码计算与word、wps有差异,不推荐使用
//_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);
_AddStdContent(p); _AddStdContent(p);
p2 := TOfficeObj('TParagraph'); p2 := TOfficeObj('TParagraph');
//p2.Format.SpaceAfter := 0; //p2.Format.SpaceAfter := 0;
run := p2.AddRun(); run := p2.AddRun();
@@ -101,7 +117,7 @@ Type TTableContent = class
run.fldCharType := 'end'; run.fldCharType := 'end';
_AddStdContent(p2); _AddStdContent(p2);
End; End;
Function _AddItem(UpperHeadingLevel, LowerHeadingLevel, level, first); Function _AddItem(UpperHeadingLevel, LowerHeadingLevel, level, first);
Begin Begin
p := TOfficeObj('TParagraph'); p := TOfficeObj('TParagraph');
@@ -112,18 +128,18 @@ 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();
r2.instrTextSpace := 'preserve'; r2.instrTextSpace := 'preserve';
r2.instrText := 'TOC \\o \"' $ UpperHeadingLevel $ '-' $ LowerHeadingLevel $ '\" \\h \\u '; r2.instrText := 'TOC \\o \"' $ UpperHeadingLevel $ '-' $ LowerHeadingLevel $ '\" \\h \\z \\u ';
//fldCharType //fldCharType
r3 := p.AddRun(); r3 := p.AddRun();
@@ -136,155 +152,165 @@ 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
r4 := p.AddRun(); h := p.AddHyperLink();
r4.fldCharType := 'begin';
//instrText
bookmarke := _GetBookMarkId(r[i]['Paragraph']); bookmarke := _GetBookMarkId(r[i]['Paragraph']);
r5 := p.AddRun(); h.Anchor := bookmarke;
r5.instrTextSpace := 'preserve'; h.history := 1;
r5.instrText := ' HYPERLINK \\l ' $ bookmarke $ ' ';
r1 := h.AddRun();
//fldCharType r1.rPr.StyleId := _GetStyle(level);
r6 := p.AddRun(); r1.rPr.noProof := true;
r6.fldCharType := 'separate';
//目录条目文字内容
r7 := p.AddRun();
r7.Font.SetName('宋体', true);
numStr := ''; //数字项目编号 numStr := ''; //数字项目编号
if r[i]['numId'] then Begin if r[i]['numId'] then Begin
style := docx_.NumberingObject().NumberStyle(r[i]['numId']);//支持数字、字符串StyleId style := docx_.NumberingObject().NumberStyle(r[i]['numId']);//支持数字、字符串StyleId
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
r7.T := numStr + r[i]['Text']; run_t := class(TSXml).CurCodePageToUtf8(r[i]['Text']);
if numStr <> '' then run_t := numStr + ' ' + run_t;
//Tab r1.SetText(run_t, 1);
r8 := p.AddRun();
r8.Tab := true; r2 := h.AddRun();
r2.rPr.noProof := true;
//fldCharType r2.rPr.WebHidden := true;
r9 := p.AddRun(); r2.Tab := true;
r9.fldCharType := 'begin';
r3 := h.AddRun();
r3.rPr.noProof := true;
r3.rPr.WebHidden := true;
r3.fldCharType := 'begin';
//instrText //instrText
r10 := p.AddRun(); r4 := h.AddRun();
r10.instrTextSpace := 'preserve'; r4.rPr.noProof := true;
r10.instrText := ' PAGEREF ' $ bookmarke $ ' \\h '; r4.rPr.WebHidden := true;
r4.instrTextSpace := 'preserve';
r4.instrText := ' PAGEREF ' $ bookmarke $ ' \\h ';
r5 := h.AddRun();
r5.rPr.noProof := true;
r5.rPr.WebHidden := true;
r5.Tab := true;
//fldCharType //fldCharType
r11 := p.AddRun(); r6 := h.AddRun();
r11.fldCharType := 'separate'; r6.rPr.noProof := true;
r6.rPr.WebHidden := true;
r6.fldCharType := 'separate';
//页码 //页码
r12 := p.AddRun(); r7 := h.AddRun();
r12.T := '' $ r[i]['pageNo']; r7.T := 0;//'' $ r[i]['pageNo'];
//fldCharType //fldCharType
r13 := p.AddRun(); r8 := h.AddRun();
r13.fldCharType := 'end'; r8.rPr.noProof := true;
r8.rPr.WebHidden := true;
//fldCharType r8.fldCharType := 'end';
r14 := p.AddRun();
r14.fldCharType := 'end';
if r[i]['Level']+1 = UpperHeadingLevel then Begin //第一级标题,设置为粗体
p.Format.rPr.Bold := true;
r4.rPr.Bold := true;
r5.rPr.Bold := true;
r6.rPr.Bold := true;
r7.rPr.Bold := true;
r8.rPr.Bold := true;
//r9.rPr.Bold := true;
r10.rPr.Bold := true;
//r11.rPr.Bold := true;
r12.Font.Bold := true;
//r13.rPr.Bold := true;
r14.rPr.Bold := true;
End;
_AddStdContent(p); _AddStdContent(p);
End; End;
p2 := TOfficeObj('TParagraph');
//p2.Format.SpaceAfter := 0;
run := p2.AddRun();
run.rPr.Bold := true;
run.rPr.noProof := true;
run.fldCharType := 'end';
_AddStdContent(p2);
End; End;
///更新目录 ///更新目录
Function UpdatePageNumbers(); Function UpdatePageNumbers();
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();
End; End;
Property Format read readFormat; Property Format read readFormat;
Function readFormat(); Function readFormat();
Begin Begin
return impl_.stdPr; return impl_.sdtPr;
End; End;
Property EndFormat read readEndFormat; Property EndFormat read readEndFormat;
Function readEndFormat(); Function readEndFormat();
Begin Begin
return impl_.stdEndPr; return impl_.sdtEndPr;
End; End;
Property Font read readFont; Property Font read readFont;
Function readFont(); Function readFont();
Begin Begin
return impl_.stdPr.rPr; return impl_.sdtPr.rPr;
End; End;
Function _AddStdContent(o); Function _AddStdContent(o);
Begin Begin
impl_.SdtContent.NewChildNode( array("field":"", "name":"w:p", "obj":o, "attrEx":"", "nodeType":"") ); impl_.SdtContent.NewChildNode( array("field":"", "name":"w:p", "obj":o, "attrEx":"", "nodeType":"") );
End; End;
Function _GetStyle(level); Function _GetStyle(level);
Begin Begin
styleName := 'Tinysoft目录 ' $ (level + 1); styleName := ifstring(level) ? level : 'TOC' $ (level + 1);
style := docx_.StyleObject().GetStyle(styleName); style := docx_.StyleObject().GetStyleById(styleName);
if not ifObj(style) then Begin if not ifObj(style) then Begin
style := TOfficeObj('TDocxStyle'); style := docx_.StyleObject().AddDefaultStyle(styleName);
style.wType := 'paragraph';
style.CustomStyle := 1;
style.Name := styleName;
style.uiPriority := 0;
style.pPr.LeftChars := 200 * level;
style.rPr.Size := 20;
style.rPr.SzCs := 20;
docx_.StyleObject().AddStyle(style, 'TsToc' $ (level + 1));
End; End;
return style.StyleId; return style.StyleId;
End; End;
Function _GetBookMarkId(p); Function _GetBookMarkId(p);
Begin Begin
node := p.node_.FirstChildElement('w:bookmarkStart'); node := p.node_.FirstChildElement('w:bookmarkStart');
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);
Begin Begin
z := docx_.Zip(); z := docx_.Zip();
xml := z.Get('word/' + name); xml := z.Get('word/' + name);
if not ifObj(xml) then Begin if not ifObj(xml) then Begin
xmlData := TOfficeTemplate(name); xmlData := TOfficeTemplate(name);
if not ifString(xmlData) then if not ifString(xmlData) then
return ; return ;
z.Add('word/' + name, xmlData); z.Add('word/' + name, xmlData);
rels := 'word/_rels/document.xml.rels'; rels := 'word/_rels/document.xml.rels';
relsObj := z.Get(rels); relsObj := z.Get(rels);
[rId, target] := class(TSXml).FindRelationshipRid(relsObj, ''); [rId, target] := class(TSXml).FindRelationshipRid(relsObj, '');
rId ++; rId ++;
if name = 'endnotes.xml' then Begin if name = 'endnotes.xml' then Begin
class(TSXml).AddRelationshipRid(relsObj, name, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes', 'rId' $ rId); class(TSXml).AddRelationshipRid(relsObj, name, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes', 'rId' $ rId);
contentType := z.Get('[Content_Types].xml'); contentType := z.Get('[Content_Types].xml');
@@ -297,8 +323,9 @@ Type TTableContent = class
End; End;
End; End;
End; End;
docx_; [weakref]docx_;
node_; node_;
impl_; impl_;
End; End;
+8 -2
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;
@@ -19,6 +20,11 @@ Type docxDocument = Class
Begin Begin
return body_; return body_;
End; End;
Function AddNameSpace(prefix, uri);
Begin
root_.SetAttribute('xmlns:' + prefix, uri);
End;
Function GetBookMarkID(); Function GetBookMarkID();
Begin 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;
@@ -48,4 +54,4 @@ private
body_; body_;
document_; document_;
bookmarkid_; bookmarkid_;
End; End;
@@ -1,6 +0,0 @@
Function _ExcelChartCopyPic(excelFileName, excelSheetName, chartName, Width, Height);
Begin
docx := TOfficeApi().GetDocument();
chart := docx.CopyExcelChart(excelFileName, excelSheetName, chartName, Width, Height, TOfficeApi().GetCurrentPosition());
return ifObj(chart);
End;
@@ -1,3 +0,0 @@
Function _WordAddOleObjectFromFile(fileName, width, height);
Begin
End;
-5
View File
@@ -1,5 +0,0 @@
Function _WordBr();
Begin
TOfficeApi().GetDocument().AddLineBreak(TOfficeApi().Get('CurrentPosition'));
End;
@@ -1,34 +0,0 @@
Function _WordCopyFromExcel(excelFileName, excelSheetName, startRow, startCol, endRow, endCol);
Begin
excel := new TSExcelFile();
[err, msg] := excel.OpenFile('', excelFileName);
if err then return false;
total_row := excel.TotalRows(excelSheetName);
total_col := excel.TotalCols(excelSheetName);
if not total_row or not total_col then return false;
if ifnil(startRow) then
startRow := 1;
if ifnil(startCol) then
startCol := 1;
if ifnil(endRow) then
endRow := total_row;
if ifnil(endCol) then
endCol := total_col;
data := excel.GetTable(excelSheetName,
CoordinatesToCellName(startCol, startRow),
CoordinatesToCellName(endCol, endRow),
false,
false,
false);
if length(data) = 0 then return false;
//println('data={}',data);
docx := TOfficeApi().GetDocument();
tbl := docx.CreateTable(data, false, false);
tbl.Format.Borders.Top.Val := 'dashed';
tbl.Format.Borders.Left.Val := 'dashed';
tbl.Format.Borders.Bottom.Val := 'dashed';
tbl.Format.Borders.Right.Val := 'dashed';
tbl.Format.Borders.InsideH.Val := 'dashed';
tbl.Format.Borders.InsideV.Val := 'dashed';
tbl := docx.InsertTable(tbl, TOfficeApi().GetCurrentPosition());
End;
@@ -1,3 +0,0 @@
Function _WordCopyPicFormatExcel(excelFileName, excelSheetName, startRow, startCol, endRow, endCol, picType);
Begin
End;
@@ -1,4 +0,0 @@
Function _WordGetCurrentDocument();
Begin
return TOfficeApi().GetDocument();
End;
@@ -1,4 +0,0 @@
Function _WordGetCurrentRange();
Begin
return TOfficeApi().GetCurrentPosition();
End;
-10
View File
@@ -1,10 +0,0 @@
Function _WordGetFont(prop, value);
Begin
crun := TOfficeApi().GetCurrentRun();
node := crun.Node().FirstChildElement('w:rPr');
rPr := TOfficeObj('TwrPr');
rPr.InitRootNode(node);
value := rPr.Value(prop);
if not ifnil(value) then return true;
return false;
End;
@@ -1,4 +0,0 @@
Function _WordGetLastRange();
Begin
return TOfficeApi().GetCurrentPosition();
End;
@@ -1,16 +0,0 @@
Function _WordGetLastShape();
Begin
node := TOfficeApi().Get('CurrentShape');
if not ifObj(node) then return nil;
uri := 'w:r/w:drawing/wp:inline/a:graphic/a:graphicData/c:chart';
cNode := class(TSXml).GetNode(node, uri);
if ifObj(cNode) then Begin
chart := TOfficeObj('TChart');
chart.Init(TOfficeApi().GetDocument(), node, cNode);
return chart;
End;
pic := TOfficeObj('TPicture');
pic.Init(node);
return pic;
End;
@@ -1,4 +0,0 @@
Function _WordGetLastTable();
Begin
return TOfficeApi().Get('LastTable');
End;
@@ -1,12 +0,0 @@
Function _WordGetLastTableCellProp(row, col, name, value);
Begin
table := TOfficeApi().Get('LastTable');
if ifnil(table) then return false;
table_cell := table.Cell(row, col);
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'return table_cell.Format.' $ name_ $ '"' $ value $ '"';
value := eval(&str);
return true;
End;
@@ -1,11 +0,0 @@
Function _WordGetLastTableProp(name, value);
Begin
table := TOfficeApi().Get('LastTable');
if ifnil(table) then return false;
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'return table.Format.' $ name_ $ '"' $ value $ '"';
value := eval(&str);
return true;
End;
@@ -1,3 +0,0 @@
Function _WordGetRangeProp(name, value);
Begin
End;
@@ -1,11 +0,0 @@
Function _WordLastTableMerge(row1, col1, row2, col2);
Begin
table := TOfficeApi().Get('LastTable');
if ifnil(table) then return false;
[err1, beg_cell] := CoordinatesToCellName(col1, row1);
[err2, end_cell] := CoordinatesToCellName(col2, row2);
if err1 or err2 then return false;
table.Merge(beg_cell, end_cell, false);
TOfficeApi().Set('LastTable', table);
return true;
End;
@@ -1,3 +0,0 @@
Function _WordLastTableSplit(row, col, rCnt, cCnt);
Begin
End;
@@ -1,4 +0,0 @@
Function _WordSetCurrnetRange(range);
Begin
TOfficeApi().Set('CurrentPosition', range);
End;
-8
View File
@@ -1,8 +0,0 @@
Function _WordSetFont(prop, value);
Begin
run := TOfficeApi().GetCurrentRun();
str := 'run.font.' $ prop $ ' := ' $ '"' $ value $ '"';
eval(&str);
run.Apply();
return true;
End;
@@ -1,17 +0,0 @@
Function _WordSetLastTableCellProp(row, col, name, value);
Begin
table := TOfficeApi().Get('LastTable');
if ifnil(table) then return false;
table_cell := table.Cell(row, col);
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'table_cell.Format.' $ name_ $ ' := ';
if ifstring(value) then
str += '"' $ value $ '"';
else
str = str $ value;
eval(&str);
TOfficeApi().Set('LastTable', table);
return true;
End;
@@ -1,17 +0,0 @@
Function _WordSetLastTableProp(name, value);
Begin
table := TOfficeApi().Get('LastTable');
if ifnil(table) then return false;
ctr := _wordCompTable();
name_ := ctr[lowercase(name)];
if ifnil(name_) then name_ := name;
str := 'table.Format.' $ name_ $ ' := ';
if ifstring(value) then
str += '"' $ value $ '"';
else
str = str $ value;
eval(&str);
TOfficeApi().Set('LastTable', table);
return true;
End;
@@ -1,5 +0,0 @@
Function _WordSetRangeProp(name, value);
Begin
cur := TOfficeApi().GetCurrentPosition();
if ifnil(cur) then return nil;
End;
-14
View File
@@ -1,14 +0,0 @@
Function _WordTemplate(data, template, fileName);
Begin
setsysparam('data', data);
docx := new TSDocxFile();
[err, msg] := docx.OpenFile('', template);
if err then return false;
docx.ExecInnerTSL();
if ifstring(fileName) then
begin
[err, msg] := docx.SaveAs('', fileName);
if err then return false;
end
return true;
End;
-17
View File
@@ -1,17 +0,0 @@
Function _WordWrite();
Begin
docx := TOfficeApi().GetDocument();
curParagraph := TOfficeApi().GetCurrentParagraph();
curRun := TOfficeApi().GetCurrentRun();
for i:=1 to PARAMCOUNT do Begin
argv := params[i];
if ifstring( argv ) then
curRun.AddText( argv );
else if ifnumber(argv) then
curRun.AddText('' $ argv);
else if ifarray(argv) then Begin
tbl := docx.CreateTable(argv, false, false);
tbl := docx.InsertTable(tbl, TOfficeApi().GetCurrentPosition());
End
End
End;
@@ -1,11 +0,0 @@
Function _WordWritePicFromFile(fileName);
Begin
file_size := fileSize('', fileName);
flag := readfile(rwbinary(), '', fileName, 0, file_size, data);
if not flag then return false;
picture := TOfficeObj('TPicture');
picture.Image := data;
docx := TOfficeApi().GetDocument();
docx.AddPicture(picture, TOfficeApi().GetCurrentPosition());
return true;
End;
@@ -1,8 +0,0 @@
Function _WordWriteTable(table, writeIntIndex, writeIntTitle, incIntIndex);
Begin
docx := TOfficeApi().GetDocument();
tbl := docx.CreateTable(table, true, writeIntIndex);
table := docx.InsertTable(tbl, TOfficeApi().GetCurrentPosition());
TOfficeApi().Set('LastTable', table);
return true;
End;
-10
View File
@@ -1,10 +0,0 @@
Function _wordCompTable();
Begin
return array(
'alignment': 'Alignment',
'shadingcolor': 'Shading.Color',
'style': 'StyleID',
'verticalalignment': 'Valign',
'width': 'Width',
);
End;
-26
View File
@@ -1,26 +0,0 @@
_WordTemplate(alias, fileName);
_WordCopyFromExcel(excelFileName, excelSheetName, startRow, startCol, endRow, endCol);
_WordCopyPicFromExcel(excelFileName, excelSheetName, startRow, startCol, endRow, endCol, picType);
_ExcelChartCopyPic(excelFileName, excelSheetName, picType);
_WordGetCurrentDocument();
_WordGetCurrentRange();
_WordSetCurrnetRange(range);
_WordGetLastRange();
_WordGetLastTable();
_WordGetLastShape();
_WordWrite();
_WordBr();
_WordWriteTable(table, writeIntIndex, writeIntTile, incIntIndex);
_WordWritePicFromFile(fileName);
_WordSetFont(prop, value);
_WordGetFont(prop, value);
_WordAddOleObjectFromFile(fileName, width, height);
_WordLastTableSplit(row, col, rCnt, cCnt);
_WordLastTableMerge(row1, col1, row2, col2);
_WordSetRangeProp(name, value);
_WordGetRangeProp(name, value);
_WordSetLastTableProp(name, value);
_WordGetLastTableProp(name, value);
_WordSetLastTableCellProp(row, col, name, value);
_WordGetLastTableCellProp(row, col, name, value);
+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_;
+7 -3
View File
@@ -124,7 +124,7 @@ xmlns:v="urn:schemas-microsoft-com:vml">
if ifObj(node) then Begin if ifObj(node) then Begin
[err, col, row] := excel_.CellNameToCoordinates(cell); [err, col, row] := excel_.CellNameToCoordinates(cell);
clientData := TOfficeObj('TClientData'); clientData := TOfficeObj('TClientData');
clientData.Anchor := fmt('{},23,{},0,{},{},{},5',col, row, 1+col+lineCount, colCount+col-1, 1+row+lineCount); clientData.Anchor := format('%d,23,%d,0,%d,%d,%d,5',col, row, 1+col+lineCount, colCount+col-1, 1+row+lineCount);
clientData.Row := row - 1; clientData.Row := row - 1;
ClientData.Column := col - 1; ClientData.Column := col - 1;
node.UnMarshal(clientData.Marshal()); node.UnMarshal(clientData.Marshal());
@@ -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"日"
+2 -2
View File
@@ -101,7 +101,7 @@ private
name := "列" $ col_index++; name := "列" $ col_index++;
excel_.WorkBook().SetCellValue(sheetName_, cell, name); excel_.WorkBook().SetCellValue(sheetName_, cell, name);
end end
table_str += fmt('<tableColumn id="{}" name="{}" />', id++, name); table_str += format('<tableColumn id="%d" name="%s" />', id, name);
end end
table_str += "</tableColumns>"; table_str += "</tableColumns>";
@@ -126,7 +126,7 @@ private
private private
sheetName_:string; //sheet名称 sheetName_:string; //sheet名称
excel_;//TSExcelFile对象 [weakref]excel_;//TSExcelFile对象
zipfile_; zipfile_;
tableXmlFile_; tableXmlFile_;
End; End;
File diff suppressed because it is too large Load Diff
+839 -293
View File
File diff suppressed because it is too large Load Diff