This commit is contained in:
csh 2023-09-27 14:50:53 +08:00
parent d72d88d68a
commit 9c917cfb70
8 changed files with 177 additions and 92 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,4 @@
// Version 1.4.7 // Version 1.4.8
Function TOfficeObj(n); Function TOfficeObj(n);
Begin Begin
@ -7385,9 +7385,6 @@ type TParagraphImpl=class(NodeInfo)
markStart := new TBookMark(self, 'w:bookmarkStart'); markStart := new TBookMark(self, 'w:bookmarkStart');
Run := new TRun(self, 'w:r'); Run := new TRun(self, 'w:r');
markEnd := new TBookMark(self, 'w:bookmarkEnd'); markEnd := new TBookMark(self, 'w:bookmarkEnd');
PageNo := new TFldSimple(self, 'w:fldSimple');
OfRun := new TRun(self, 'w:r');
TotalPageNo := new TFldSimple(self, 'w:fldSimple');
//TODO... //TODO...
End; End;
@ -7398,9 +7395,6 @@ type TParagraphImpl=class(NodeInfo)
markStart.InitRootNode(node); markStart.InitRootNode(node);
Run.InitRootNode(node); Run.InitRootNode(node);
markEnd.InitRootNode(node); markEnd.InitRootNode(node);
PageNo.InitRootNode(node);
OfRun.InitRootNode(node);
TotalPageNo.InitRootNode(node);
End; End;
Function GetAttrs(); override; Function GetAttrs(); override;
@ -7416,9 +7410,6 @@ type TParagraphImpl=class(NodeInfo)
,('field':'markStart','name':markStart.NodeName,'obj':markStart,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TBookMark') ,('field':'markStart','name':markStart.NodeName,'obj':markStart,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TBookMark')
,('field':'Run','name':Run.NodeName,'obj':Run,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TRun') ,('field':'Run','name':Run.NodeName,'obj':Run,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TRun')
,('field':'markEnd','name':markEnd.NodeName,'obj':markEnd,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TBookMark') ,('field':'markEnd','name':markEnd.NodeName,'obj':markEnd,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TBookMark')
,('field':'PageNo','name':PageNo.NodeName,'obj':PageNo,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TFldSimple')
,('field':'OfRun','name':OfRun.NodeName,'obj':OfRun,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TRun')
,('field':'TotalPageNo','name':TotalPageNo.NodeName,'obj':TotalPageNo,'attrEx':'','nodeType':'','attrName':'', 'desc':'', 'class':'TFldSimple')
) union ExtNodes; ) union ExtNodes;
End; End;
@ -7429,9 +7420,6 @@ type TParagraphImpl=class(NodeInfo)
markStart; markStart;
Run; Run;
markEnd; markEnd;
PageNo;
OfRun;
TotalPageNo;
End; End;
/////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
@ -11130,6 +11118,17 @@ Type TParagraph = Class(DocObject, TParagraphImpl)
end end
return false; return false;
End; End;
///获取当前段落的上一个段落
///返回TParagraph对象
Function PrevParagraph();
Begin
if ifObj(node_) then
begin
node := node_.PrevElement('w:p');
return ifObj(node) ? new TParagraph(node) : nil;
end
End;
Function CopyRunFormat(del, toRunNode); Function CopyRunFormat(del, toRunNode);
Begin Begin
@ -12980,6 +12979,14 @@ Type TDocumentBody = Class(DocObject)
End; End;
return r; return r;
End; End;
///word最后一个段落
///返回TParagraph对象
Function LastParagraph();
Begin
node := node_.LastChildElement('w:p');
return ifObj(node) ? new TParagraph(node) : nil;
End;
///添加新段落 ///添加新段落
///paragraph: TParagraph对象 ///paragraph: TParagraph对象
@ -13040,7 +13047,7 @@ Type TDocumentBody = Class(DocObject)
if not ifObj(node) then if not ifObj(node) then
return false; return false;
reset_position := false; reset_position := false;
if node.Eq(TOfficeApi().GetCurrentPosition()) then if ifObj(TOfficeApi().GetCurrentPosition()) and node.Eq(TOfficeApi().GetCurrentPosition()) then
reset_position := true; reset_position := true;
next := node.NextElement('w:p'); next := node.NextElement('w:p');
node_.DeleteChild(node); node_.DeleteChild(node);
@ -13128,7 +13135,7 @@ Type TDocumentBody = Class(DocObject)
///插入数据表 ///插入数据表
///tbl: TTable对象 ///tbl: TTable对象
///[posOpt: 段落位置]0 在DOCX文件开头-1 文件尾N 在第N段之后DocumentPart对象 在posOpt之后新添加表格 ///[posOpt: 段落位置]0 在DOCX文件开头-1 文件尾N 在第N段之后DocumentPart对象 在posOpt之后新添加表格
Function InsertTable(tbl, posOpt); Function InsertTable(tbl, posOpt, customCell);
Begin Begin
addPart(posOpt, tbl); addPart(posOpt, tbl);
TOfficeApi().Set('CurrentTable', tbl.node_); TOfficeApi().Set('CurrentTable', tbl.node_);
@ -13166,10 +13173,17 @@ Type TDocumentBody = Class(DocObject)
End; End;
tcNode := trNode.InsertEndChild('element', 'w:tc'); tcNode := trNode.InsertEndChild('element', 'w:tc');
tcPrNode := tcNode.InsertEndChild('element', 'w:tcPr'); if istable(customCell) and ifObj(customCell[i, j, 0]) then
tcWNode := tcPrNode.InsertEndChild('element', 'w:tcW'); begin
tcWNode.SetAttribute('w:w', tbl.TblGrid.GridCol[j]['obj'].W); tcNode.InsertEndChild(customCell[i, j, 0].Marshal());
tcWNode.SetAttribute('w:type', 'dxa'); end
else begin
tcPrNode := tcNode.InsertEndChild('element', 'w:tcPr');
tcWNode := tcPrNode.InsertEndChild('element', 'w:tcW');
tcWNode.SetAttribute('w:w', tbl.TblGrid.GridCol[j]['obj'].W);
tcWNode.SetAttribute('w:type', 'dxa');
end
if multiLine then Begin if multiLine then Begin
defaultParagraph.node_ := nil; defaultParagraph.node_ := nil;
defaultParagraph.Run.ClearText(); defaultParagraph.Run.ClearText();
@ -13178,9 +13192,15 @@ Type TDocumentBody = Class(DocObject)
End End
else Begin else Begin
pNode := tcNode.InsertEndChild('element', 'w:p'); pNode := tcNode.InsertEndChild('element', 'w:p');
pNode.InsertEndChild(defaultpPr); if istable(customCell) and ifObj(customCell[i, j, 1]) then
pNode.InsertEndChild(customCell[i, j, 1].Marshal());
else
pNode.InsertEndChild(defaultpPr);
rNode := pNode.InsertEndChild('element', 'w:r'); rNode := pNode.InsertEndChild('element', 'w:r');
rNode.InsertEndChild(defaultrPr); if istable(customCell) and ifObj(customCell[i, j, 2]) then
rNode.InsertEndChild(customCell[i, j, 2].Marshal());
else
rNode.InsertEndChild(defaultrPr);
tNode := rNode.InsertEndChild('element','w:t', class(TSXml).CurCodePageToUtf8(tbl.Data_[i, j])); tNode := rNode.InsertEndChild('element','w:t', class(TSXml).CurCodePageToUtf8(tbl.Data_[i, j]));
if _preserve(tbl.Data_[i, j]) then if _preserve(tbl.Data_[i, j]) then
tNode.SetAttribute('xml:space', 'preserve'); tNode.SetAttribute('xml:space', 'preserve');
@ -13908,54 +13928,44 @@ Type TDocumentBody = Class(DocObject)
pNode := posOpt.NextElement(); pNode := posOpt.NextElement();
else else
pNode := node_.FirstChildElement(); pNode := node_.FirstChildElement();
sectPr := new TSectPr(docx, nil);
while ifObj(pNode) do Begin while ifObj(pNode) do Begin
name := pNode.GetName(); name := pNode.GetName();
if false and ifarray(numIds) and name = 'w:sectPr' then // 关闭此处的Init计算页码 if name = 'w:p' and not ifObj(pNode.FirstChildElement('w:sectPr')) then
sectPr.Init(pNode); begin
else if name = 'w:p' then Begin p := new TParagraph(pNode);
sectNode := pNode.FirstChildElement('w:sectPr'); //统计数字项目编号
if ifObj(sectNode) then Begin //章节 numArr := array();
sectPr.Init(pNode); numId := getNumPr('numId', docx, p);
End ilvl := getNumPr('Level', docx, p);
else Begin if not ilvl then ilvl := 0;
p := new TParagraph(pNode); if ifarray(numIds) then Begin
//统计数字项目编号 if ilvl >= 0 and ilvl < 10 then Begin
numArr := array(); if not istable(numIds[numId]) then
numId := getNumPr('numId', docx, p); numIds[numId] := array(0,0,0,0,0,0,0,0,0,0);
ilvl := getNumPr('Level', docx, p); prev := numIds[numId, ilvl];
if not ilvl then ilvl := 0; if prev then Begin
if ifarray(numIds) then Begin for i:=ilvl+1 to 9 do
sectPr.Append(p); numIds[numId, i] := 0;
if ilvl >= 0 and ilvl < 10 then Begin
if not istable(numIds[numId]) then
numIds[numId] := array(0,0,0,0,0,0,0,0,0,0);
prev := numIds[numId, ilvl];
if prev then Begin
for i:=ilvl+1 to 9 do
numIds[numId, i] := 0;
End;
numIds[numId, ilvl]++;
numArr := numIds[numId];
End; End;
numIds[numId, ilvl]++;
numArr := numIds[numId];
End; End;
if bHeadList then Begin //统计大纲显示(目录) End;
styleId := p.Format.Value('StyleId', 1); if bHeadList then Begin //统计大纲显示(目录)
if styleId <> '' then Begin styleId := p.Format.Value('StyleId', 1);
obj := docx.StyleObject().GetStyleById(styleId); if styleId <> '' then Begin
if ifObj(obj) then Begin obj := docx.StyleObject().GetStyleById(styleId);
level := getHeadingLevel(docx, obj); if ifObj(obj) then Begin
iLevel := Class(TSXml).SafeStrToIntDef(level, -1); level := getHeadingLevel(docx, obj);
if p.Text() <> "" and iLevel+1 >= UpperHeadingLevel and iLevel+1 <= LowerHeadingLevel then Begin iLevel := Class(TSXml).SafeStrToIntDef(level, -1);
r[ind]['Level'] := strtoint(level); if p.Text() <> "" and iLevel+1 >= UpperHeadingLevel and iLevel+1 <= LowerHeadingLevel then Begin
r[ind]['Paragraph'] := p; r[ind]['Level'] := strtoint(level);
r[ind]['Text'] := p.Text(); r[ind]['Paragraph'] := p;
r[ind]['numId'] := ifnumber(numId) ? integer(numId) : 0; //数字项目编号 r[ind]['Text'] := p.Text();
r[ind]['ilvl'] := ilvl; //级别 r[ind]['numId'] := ifnumber(numId) ? integer(numId) : 0; //数字项目编号
r[ind]['numArr'] := numArr; //累加数字编码 r[ind]['ilvl'] := ilvl; //级别
sectPr.Mark(ind);//标记段落 r[ind]['numArr'] := numArr; //累加数字编码
ind++; ind++;
End;
End; End;
End; End;
End; End;
@ -13964,7 +13974,6 @@ Type TDocumentBody = Class(DocObject)
else if ifarray(numIds) and name = 'w:tbl' then Begin else if ifarray(numIds) and name = 'w:tbl' then Begin
tbl := TOfficeObj('TTable'); tbl := TOfficeObj('TTable');
tbl.Init(pNode); tbl.Init(pNode);
sectPr.Append(tbl);
rows := tbl.Rows(); rows := tbl.Rows();
cols := tbl.Cols(); cols := tbl.Cols();
for i:=1 to rows do Begin for i:=1 to rows do Begin
@ -13977,11 +13986,6 @@ Type TDocumentBody = Class(DocObject)
pNode := pNode.NextElement(); pNode := pNode.NextElement();
End; End;
if ifarray(numIds) then Begin //设置页面
for i:=0 to length(r)-1 do Begin
r[i]['pageNo'] := sectPr.GetPageNo(i);
End;
End;
return r; return r;
End; End;
@ -14505,8 +14509,9 @@ Type TCell = Class(TDocumentBody, TWTc)
Function Append(c); Function Append(c);
Begin Begin
ps := c.Paragraphs(); ps := c.Parts();
for i:=0 to length(ps)-1 do Begin for i:=0 to length(ps)-1 do Begin
if not ps[i].node_.GetName() in array('w:p', 'w:tbl') then continue;
data := ps[i].node_.Marshal(); data := ps[i].node_.Marshal();
w := node_.InsertEndChild(data[0]); w := node_.InsertEndChild(data[0]);
End; End;
@ -14824,6 +14829,76 @@ Type TTable = Class(DocObject, TTableImpl)
return 'Invalid input Coordinates.'; return 'Invalid input Coordinates.';
return Merge(top, left, bottom, right, del); return Merge(top, left, bottom, right, del);
End; End;
///删除单元格
///row: int, 行
///col: int, 列
///[cellshift]: int, 默认1。0:删除单元格下方内容上移1:删除单元格右侧单元格左移
///row或col其中一个为nil时删除某行或某列如(1, nil),删除第一行
Function DeleteCell(row, col, cellshift);
Begin
if ifnil(cellshift) then cellshift := 1;
if ifnumber(row) and ifnil(col) then
begin
node := _getRowNode(row - 1);
if ifObj(node) then node_.DeleteChild(node);
for i:=row-1 to length(cells_)-2 do
cells_[i] := cells_[i + 1];
reindex(cells_, array(length(cells_)-1 : nil));
end
else if ifnil(row) and ifnumber(col) then
begin
for r:=1 to length(cells_) do
DeleteCell(r, col);
iCol_--;
end
else begin
c := cells_[row-1, col-1];
if not c then return;
node := _getRowNode(row - 1);
if cellshift then
begin
node.DeleteChild(c[0]);
for i:=col-1 to iCol_ - 1 do
cells_[row-1, i] := cells_[row-1, i+1];
cells_[row-1, iCol_-1] := nil;
end
else begin
r := row;
len := length(cells_);
while r < len and ifObj(node) do
begin
tcell := cells_[r, col-1];
if tcell then
begin
new_node := node.InsertAfterChild(c[0], tcell[0].Marshal()[0]);
node.DeleteChild(c[0]);
cells_[row-1, col-1, 0] := new_node;
end
c := tcell;
++r;
node := node.NextElement();
end
if c then
begin
p := c[0].FirstChild('w:p');
c[0].DeleteChildren();
c[0].InsertEndChild('element', 'w:p');
end
end
end
End;
Function _getRowNode(row);
Begin
node := node_.FirstChild('w:tr');
while row and ifObj(node) do
begin
row--;
node := node.NextElement();
end
return node;
End;
Function _getLeft(row, iCol, left2); Function _getLeft(row, iCol, left2);
Begin Begin
@ -15344,3 +15419,4 @@ Begin
return true; return true;
return false; return false;
End; End;

View File

@ -1,4 +1,4 @@
// Version 1.4.7 // Version 1.4.8
Type TSDocxFile = Class Type TSDocxFile = Class
///Version: V1.0 2022-09-20 ///Version: V1.0 2022-09-20
@ -123,6 +123,13 @@ Type TSDocxFile = Class
Begin Begin
return document_.Body().Paragraphs(); return document_.Body().Paragraphs();
End; End;
///word文档最后一个段落
///返回TParagraph对象
Function LastParagraph();
Begin
return document_.Body().LastParagraph();
End;
///添加新段落 ///添加新段落
///paragraph: TParagraph对象 ///paragraph: TParagraph对象
@ -230,10 +237,12 @@ Type TSDocxFile = Class
///插入数据表 ///插入数据表
///tbl: TTable对象 ///tbl: TTable对象
///posOpt: 段落位置0 在DOCX文件开头-1 文件尾N 在第N段之后XmlNode节点对象或DocObject对象 在posOpt之后新添加表格 ///posOpt: 段落位置0 在DOCX文件开头-1 文件尾N 在第N段之后XmlNode节点对象或DocObject对象 在posOpt之后新添加表格
///customCell: 二维数组,自定义指定单元格的样式
/// 如一行一列arr[0][0] := array(twtcPr, twpPr, twrPr);其中twtcPr是twtcPr对象twpPr是twpPr对象twrPr是twrPr对象
///返回: TTable对象 ///返回: TTable对象
Function InsertTable(tbl, posOpt); Function InsertTable(tbl, posOpt, customCell);
Begin Begin
return document_.Body().InsertTable(tbl, getPosNode(posOpt)); return document_.Body().InsertTable(tbl, getPosNode(posOpt), customCell);
End; End;
///返回CoreProperties对象 ///返回CoreProperties对象

View File

@ -1,4 +1,4 @@
// Version 1.4.7 // Version 1.4.8
Type TSExcelFile = Class Type TSExcelFile = Class
///Version: V1.0 2022-08-08 ///Version: V1.0 2022-08-08

View File

@ -71,27 +71,16 @@ public
children_ := nil; children_ := nil;
GetChildrenEx(); //优化为变量减少数据COPY2022-12-10 GetChildrenEx(); //优化为变量减少数据COPY2022-12-10
child_arr := array(); child_arr := array();
name_map := array();
len := 0; len := 0;
for i:=0 to length(children_)-1 do for i:=0 to length(children_)-1 do
begin begin
node_type := children_[i]['nodeType']; node_type := children_[i]['nodeType'];
obj := children_[i]['obj']; obj := children_[i]['obj'];
if ifnil(obj) then continue; if ifnil(obj) then continue;
//find := select thisrowindex as "rowindex_", * from child_arr where ['name'] = children_[i]['name'] end; //优化为循环性能提高15-20%2022-12-20 if not ifObj(obj) and not ifnil(name_map[children_[i]['name']]) and children_[i]['attrEx'] <> '' then
find := array();
for j:=length(child_arr)-1 downto 0 do Begin //支持列表模式(如多节点:<w:t xml:space=""></w:t>),查找最近的节点
if child_arr[j]['name'] = children_[i]['name'] then Begin
find[0] := child_arr[j];
find[0]['rowindex_'] := j;
break;
End;
End;
if not ifnil(obj) and not ifObj(obj) and istable(find) and ifstring(children_[i]['attrEx']) and children_[i]['attrEx'] <> '' then
begin begin
if not ifarray(find[0]['attributes']) then find[0]['attributes'] := array(); child_arr[name_map[children_[i]['name']]]['attributes'] union=array(children_[i]['attrEx'] : obj);
key := children_[i]['attrEx'];
find[0]['attributes'] union= array(key : obj);
child_arr[find[0]['rowindex_']]['attributes'] := find[0]['attributes'];
continue; continue;
end end
@ -118,7 +107,7 @@ public
key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val';
arr['attributes'] := array(key : obj); arr['attributes'] := array(key : obj);
end end
name_map[children_[i]['name']] := len;
child_arr[len++] := arr; child_arr[len++] := arr;
end end

View File

@ -142,7 +142,7 @@ Type TTableContent = class
Begin Begin
///获取标题列表 array((("Level":level,"Paragraph":"object","Text":title,"numId":,"ilvl":,"numArr":)); ///获取标题列表 array((("Level":level,"Paragraph":"object","Text":title,"numId":,"ilvl":,"numArr":));
numMap := array(); numMap := array();
r := docx_.Document().Body().GetHeadingListImpl(docx_, -1, UpperHeadingLevel, LowerHeadingLevel, numMap, true); r := docx_.Document().Body().GetHeadingListImpl(docx_, nil, UpperHeadingLevel, LowerHeadingLevel, numMap, true);
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

View File

@ -1,5 +1,16 @@
# 更新日志 # 更新日志
## 2023-9-27
### V1.4.8
#### word
1. 支持`Inserttable`时候加入对单元格样式的设置
2. 新增`TSDocxFile.LastParagraph`方法
3. 新增`TParagraph.PrevParagraph`方法
4. 性能优化
## 2023-9-22 ## 2023-9-22
### V1.4.7 ### V1.4.7