From 6b0f11cebb5a5312bc72a1304c0e9d868ea7d642 Mon Sep 17 00:00:00 2001 From: csh Date: Fri, 16 Jan 2026 14:32:22 +0800 Subject: [PATCH] v1.8.6 --- .gitignore | 4 + funcext/TSOffice/TOfficeObj.tsf | 11 +- funcext/TSOffice/TSDocxFile.tsf | 2 +- funcext/TSOffice/TSUtils/NodeInfo.tsf | 598 +++++++++++++------------- funcext/TSOffice/TSXlsxFile.tsf | 4 +- 更新日志.md | 12 + 6 files changed, 324 insertions(+), 307 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62fafd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.swp +*.swo +*.cmd +script.ps1 diff --git a/funcext/TSOffice/TOfficeObj.tsf b/funcext/TSOffice/TOfficeObj.tsf index b06767f..cedccef 100644 --- a/funcext/TSOffice/TOfficeObj.tsf +++ b/funcext/TSOffice/TOfficeObj.tsf @@ -1,4 +1,4 @@ -// Version 1.8.5 +// Version 1.8.6 Function TOfficeObj(n); Begin case lowercase(n) of @@ -13331,14 +13331,14 @@ Type TDocumentBody = Class(DocObject) para.Run.T := lines[0]; para.Run.RPr := para.PPr.RPr; end - for i:=1 to length(lines)-1 do Begin + for k:=1 to length(lines)-1 do Begin r := para.AddRun(); r.Br.Val := 1; r.RPr := para.PPr.RPr; r := para.AddRun(); - r.T := lines[i]; + r.T := lines[k]; r.RPr := para.PPr.RPr; - if _preserve(lines[i]) then + if _preserve(lines[k]) then begin r := para.AddRun(); r.Space := "preserve"; @@ -13559,7 +13559,8 @@ Type TDocumentBody = Class(DocObject) p := new TParagraph(); p.pPr.NewChildNode( array("field":"", "name":"w:sectPr", "obj":section, "attrEx":"", "nodeType":"") ); p := AddParagraph(p, posOpt, '');//段落对象 - sec := new TDocSection(p.node_, -2, zipfile_); + sec := new TDocSection(p.node_, -2, zipfile_); + sec.NodeUri := 'w:pPr/w:sectPr'; return sec; End; diff --git a/funcext/TSOffice/TSDocxFile.tsf b/funcext/TSOffice/TSDocxFile.tsf index 2fb6d9d..288705f 100644 --- a/funcext/TSOffice/TSDocxFile.tsf +++ b/funcext/TSOffice/TSDocxFile.tsf @@ -1,4 +1,4 @@ -// Version 1.8.5 +// Version 1.8.6 Type TSDocxFile = Class ///Version: V1.0 2022-09-20 ///适用于 Microsoft Word docx格式文件 diff --git a/funcext/TSOffice/TSUtils/NodeInfo.tsf b/funcext/TSOffice/TSUtils/NodeInfo.tsf index 0eb8225..2a70611 100644 --- a/funcext/TSOffice/TSUtils/NodeInfo.tsf +++ b/funcext/TSOffice/TSUtils/NodeInfo.tsf @@ -1,299 +1,299 @@ -Type NodeInfo = class - -public - Function Create(parentObj, name); - Begin - if ifObj(parentObj) then - NodeUri := parentObj.NodeUri = '' ? name : (parentObj.NodeUri + '/' + name); - else - NodeUri := ''; - NodeName := name; - ExtAttr := array(); - ExtNodes := array(); - ReplaceArr := array(); - End - - Function Root(); virtual; - Begin - return RootObj; - End - - Function Update(position);overload; - Begin - if ifObj(RootObj) then Begin - arr := Marshal(); - if length(arr['attributes']) or length(arr['children']) then Begin - curNode := class(TSXml).GetNode(RootObj, NodeUri, position); - if ifObj(curNode) then - class(TSXml).UpdateNode(curNode, arr['attributes'], arr['children']); - End; - End; - End; - - Function Update();overload; - Begin - self.Update("end"); - End; - - Function Delete();overload; - Begin - if ifObj(RootObj) then - begin - curNode := class(TSXml).GetNode(RootObj, NodeUri); - if ifObj(curNode) then curNode.DeleteChildren(); - end - End; - - Function Delete(name);overload; - Begin - if not ifObj(RootObj) then return false; - node := NodeUri <> '' ? class(TSXml).GetNode(RootObj, NodeUri) : RootObj; - - attrs := GetAttrsEx(); - lName := lowerCase(name); - r := sselect * from attrs where lName = lowerCase([0]) end; - if istable(r) then - begin - node.DeleteAttribute(r[1]); - return true; - end - - children := GetChildren(); - r := select * from children where lName = lowerCase(['field']) end; - if istable(r) then Begin - r := r[0]; - delete_node := node.FirstChildElement(r['name']); - if ifObj(delete_node) then - begin - node.DeleteChild(delete_node); - return true; - end - End; - return false; - End; - - Function GetAttrs(); virtual; - Begin - return ExtAttr; - End - - Function GetChildren(); virtual; - Begin - return ExtNodes; - End - - Function GetNode(index); // 返回的index的对象 - Begin - return ExtNodes[index]['obj']; - End - - Function GetCount(); // 返回当前节点的个数 - Begin - return length(ExtAttr); - End - - // arr := array(('Size', 'sz', 15), ('Style', 'style', 'line')); - Function AddAttr(arr); // 添加属性 - Begin - if not istable(arr) then return; - ExtAttr union= arr; - return 1; - End - - Function Marshal(); - Begin - children_ := nil; - GetChildrenEx(); //优化为变量,减少数据COPY,2022-12-10 - child_arr := array(); - name_map := array(); - len := 0; - for i:=0 to length(children_)-1 do - begin - node_type := children_[i]['nodeType']; - obj := children_[i]['obj']; - if ifnil(obj) then continue; - if not ifObj(obj) and not ifnil(name_map[children_[i]['name']]) and children_[i]['attrEx'] <> '' then - begin - child_arr[name_map[children_[i]['name']]]['attributes'] union=array(children_[i]['attrEx'] : obj); - continue; - end - - arr := array('type': 'element', 'name': children_[i]['name'], 'attributes': array()); - if node_type = 'empty' then // - begin - empty_name := children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; - if obj = 0 then arr['attributes'] := array(empty_name: 0); - else if obj = 1 then arr['attributes'] := array(empty_name: 1) - end - else if node_type = 'pcdata' then - begin - arr['children'] := array(('type': 'pcdata', 'value': obj)); - end - else if ifObj(obj) then - begin - marshal := obj.Marshal(); - if length(marshal['children'])=0 and length(marshal['attributes'])=0 then continue; - arr['children'] := marshal['children']; - arr['attributes'] union= marshal['attributes']; - end - else - begin - key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; - arr['attributes'] := array(key : obj); - end - name_map[children_[i]['name']] := len; - child_arr[len++] := arr; - end - - name_arr := str2array(NodeName, '/'); - tmp_arr := array('type': 'element', 'name': name_arr[length(name_arr)-1], 'children': child_arr); - for i:=length(name_arr)-2 downto 0 do - begin - tmp_arr := array('type': 'element', 'name': name_arr[i], 'children': array(tmp_arr)); - end - - attrs_arr := GetAttrs(); - tmp_arr['attributes'] := array(); - for i:=0 to length(attrs_arr)-1 do - begin - if not ifnil(attrs_arr[i, 2]) then Begin - tmp_arr['attributes'][ attrs_arr[i, 1] ] := attrs_arr[i, 2]; - End; - end - return tmp_arr; - End - - Function NewChildNode(nodeArr); - Begin - if not ifarray(nodeArr) then return 0; - if not ifstring(nodeArr['name']) then return 0; - arr := array(( - 'name': nodeArr['name'], - 'obj': nodeArr['obj'], - 'attrEx': nodeArr['attrEx'], - 'nodeType': nodeArr['nodeType'], - )); - ExtNodes union= arr; - return 1; - End - - Function Value(name, nottransferable); - Begin - if not ifObj(RootObj) then return nil; - if NodeUri <> '' then - node := class(TSXml).GetNode(RootObj, NodeUri); - else - node := RootObj; - if not ifObj(node) then return nil; - - attrs := GetAttrsEx(); - lName := lowerCase(name); - r := sselect * from attrs where lName = lowerCase([0]) end; - if istable(r) then - begin - value := node.GetAttribute(r[1]); - return nottransferable ? value : trystrtofloat(value, r) ? r : value; - end - - children := GetChildren(); - r := select * from children where lName = lowerCase(['field']) end; - if istable(r) then Begin - r := r[0]; - node := node.FirstChildElement(r['name']); - if not ifObj(node) and r['nodeType'] = 'empty' and not nottransferable then return false; - if not ifObj(node) then return nil; - if r['nodeType'] = 'pcdata' then //返回文本串 - return node.GetText(); - if ifObj(r['obj']) then //对象,返回XML串 - return node.Data(); - key := r['attrName'] ? r['attrName'] : r['attrEx'] ? r['attrEx'] : 'val'; - value := node.GetAttribute(key); - if r['nodeType'] = 'empty' and value = '' then return true; - return nottransferable ? value : trystrtofloat(value, r) ? r : value; - End; - return nil; - End; - - Function Replace(hash, bChild); - Begin - if istable(hash) then Begin - ReplaceArr := hash; - replaceNodeName(); - if bChild then Begin - r := GetChildren(); - for i:=0 to length(r)-1 do Begin - if ifObj(r[i]['obj']) then - r[i]['obj'].Replace(hash, bChild); - End; - End; - End; - End - - Function GetChildrenEx(); - Begin - if not ifarray(children_) then Begin - children_ := getChildren(); - if not istable(ReplaceArr) then Begin - for i:=0 to length(children_)-1 do Begin - if ifarray(children_[i]['obj']) then Begin - if istable(children_[i]['obj']) then - hasArr := 1; - else - children_[i]['obj'] := nil; - End; - End; - End; - if hasArr or istable(ReplaceArr) then Begin - a := array(); - for i:=0 to length(children_)-1 do Begin - if istable(ReplaceArr) then - children_[i]['name'] := ReplaceName(children_[i]['name']); - if istable(children_[i]['obj']) then Begin - a union= children_[i]['obj']; - End - else - a[ length(a) ] := children_[i]; - end; - children_ := a; - End; - End; - End; - - Function GetAttrsEx(); - Begin - return GetAttrs();//暂时没有发现需要更新属性前缀的情况 - if not istable(ReplaceArr) then return GetAttrs(); - attr := GetAttrs(); - for i:=0 to length(attr)-1 do - attr[i][1] := ReplaceName(attr[i][1]); - return attr; - End - -private - Function replaceNodeName(); - Begin - for k, v in ReplaceArr do - 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 +Type NodeInfo = class + +public + Function Create(parentObj, name); + Begin + if ifObj(parentObj) then + NodeUri := parentObj.NodeUri = '' ? name : (parentObj.NodeUri + '/' + name); + else + NodeUri := ''; + NodeName := name; + ExtAttr := array(); + ExtNodes := array(); + ReplaceArr := array(); + End + + Function Root(); virtual; + Begin + return RootObj; + End + + Function Update(position);overload; + Begin + if ifObj(RootObj) then Begin + arr := Marshal(); + if length(arr['attributes']) or length(arr['children']) then Begin + curNode := class(TSXml).GetNode(RootObj, NodeUri, position); + if ifObj(curNode) then + class(TSXml).UpdateNode(curNode, arr['attributes'], arr['children']); + End; + End; + End; + + Function Update();overload; + Begin + self.Update("end"); + End; + + Function Delete();overload; + Begin + if ifObj(RootObj) then + begin + curNode := class(TSXml).GetNode(RootObj, NodeUri); + if ifObj(curNode) then curNode.DeleteChildren(); + end + End; + + Function Delete(name);overload; + Begin + if not ifObj(RootObj) then return false; + node := NodeUri <> '' ? class(TSXml).GetNode(RootObj, NodeUri) : RootObj; + + attrs := GetAttrsEx(); + lName := lowerCase(name); + r := sselect * from attrs where lName = lowerCase([0]) end; + if istable(r) then + begin + node.DeleteAttribute(r[1]); + return true; + end + + children := GetChildren(); + r := select * from children where lName = lowerCase(['field']) end; + if istable(r) then Begin + r := r[0]; + delete_node := node.FirstChildElement(r['name']); + if ifObj(delete_node) then + begin + node.DeleteChild(delete_node); + return true; + end + End; + return false; + End; + + Function GetAttrs(); virtual; + Begin + return ExtAttr; + End + + Function GetChildren(); virtual; + Begin + return ExtNodes; + End + + Function GetNode(index); // 返回的index的对象 + Begin + return ExtNodes[index]['obj']; + End + + Function GetCount(); // 返回当前节点的个数 + Begin + return length(ExtAttr); + End + + // arr := array(('Size', 'sz', 15), ('Style', 'style', 'line')); + Function AddAttr(arr); // 添加属性 + Begin + if not istable(arr) then return; + ExtAttr union= arr; + return 1; + End + + Function Marshal(); + Begin + children_ := nil; + GetChildrenEx(); //优化为变量,减少数据COPY,2022-12-10 + child_arr := array(); + name_map := array(); + len := 0; + for i:=0 to length(children_)-1 do + begin + node_type := children_[i]['nodeType']; + obj := children_[i]['obj']; + if ifnil(obj) then continue; + if not ifObj(obj) and not ifnil(name_map[children_[i]['name']]) and children_[i]['attrEx'] <> '' then + begin + child_arr[name_map[children_[i]['name']]]['attributes'] union=array(children_[i]['attrEx'] : obj); + continue; + end + + arr := array('type': 'element', 'name': children_[i]['name'], 'attributes': array()); + if node_type = 'empty' then // + begin + empty_name := children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; + if obj = 0 then arr['attributes'] := array(empty_name: 0); + else if obj = 1 then arr['attributes'] := array(empty_name: 1); + end + else if node_type = 'pcdata' then + begin + arr['children'] := array(('type': 'pcdata', 'value': obj)); + end + else if ifObj(obj) then + begin + marshal := obj.Marshal(); + if length(marshal['children'])=0 and length(marshal['attributes'])=0 then continue; + arr['children'] := marshal['children']; + arr['attributes'] union= marshal['attributes']; + end + else + begin + key := children_[i]['attrName'] ? children_[i]['attrName'] : children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; + arr['attributes'] := array(key : obj); + end + name_map[children_[i]['name']] := len; + child_arr[len++] := arr; + end + + name_arr := str2array(NodeName, '/'); + tmp_arr := array('type': 'element', 'name': name_arr[length(name_arr)-1], 'children': child_arr); + for i:=length(name_arr)-2 downto 0 do + begin + tmp_arr := array('type': 'element', 'name': name_arr[i], 'children': array(tmp_arr)); + end + + attrs_arr := GetAttrs(); + tmp_arr['attributes'] := array(); + for i:=0 to length(attrs_arr)-1 do + begin + if not ifnil(attrs_arr[i, 2]) then Begin + tmp_arr['attributes'][ attrs_arr[i, 1] ] := attrs_arr[i, 2]; + End; + end + return tmp_arr; + End + + Function NewChildNode(nodeArr); + Begin + if not ifarray(nodeArr) then return 0; + if not ifstring(nodeArr['name']) then return 0; + arr := array(( + 'name': nodeArr['name'], + 'obj': nodeArr['obj'], + 'attrEx': nodeArr['attrEx'], + 'nodeType': nodeArr['nodeType'], + )); + ExtNodes union= arr; + return 1; + End + + Function Value(name, nottransferable); + Begin + if not ifObj(RootObj) then return nil; + if NodeUri <> '' then + node := class(TSXml).GetNode(RootObj, NodeUri); + else + node := RootObj; + if not ifObj(node) then return nil; + + attrs := GetAttrsEx(); + lName := lowerCase(name); + r := sselect * from attrs where lName = lowerCase([0]) end; + if istable(r) then + begin + value := node.GetAttribute(r[1]); + return nottransferable ? value : trystrtofloat(value, r) ? r : value; + end + + children := GetChildren(); + r := select * from children where lName = lowerCase(['field']) end; + if istable(r) then Begin + r := r[0]; + node := node.FirstChildElement(r['name']); + if not ifObj(node) and r['nodeType'] = 'empty' and not nottransferable then return false; + if not ifObj(node) then return nil; + if r['nodeType'] = 'pcdata' then //返回文本串 + return node.GetText(); + if ifObj(r['obj']) then //对象,返回XML串 + return node.Data(); + key := r['attrName'] ? r['attrName'] : r['attrEx'] ? r['attrEx'] : 'val'; + value := node.GetAttribute(key); + if r['nodeType'] = 'empty' and value = '' then return true; + return nottransferable ? value : trystrtofloat(value, r) ? r : value; + End; + return nil; + End; + + Function Replace(hash, bChild); + Begin + if istable(hash) then Begin + ReplaceArr := hash; + replaceNodeName(); + if bChild then Begin + r := GetChildren(); + for i:=0 to length(r)-1 do Begin + if ifObj(r[i]['obj']) then + r[i]['obj'].Replace(hash, bChild); + End; + End; + End; + End + + Function GetChildrenEx(); + Begin + if not ifarray(children_) then Begin + children_ := getChildren(); + if not istable(ReplaceArr) then Begin + for i:=0 to length(children_)-1 do Begin + if ifarray(children_[i]['obj']) then Begin + if istable(children_[i]['obj']) then + hasArr := 1; + else + children_[i]['obj'] := nil; + End; + End; + End; + if hasArr or istable(ReplaceArr) then Begin + a := array(); + for i:=0 to length(children_)-1 do Begin + if istable(ReplaceArr) then + children_[i]['name'] := ReplaceName(children_[i]['name']); + if istable(children_[i]['obj']) then Begin + a union= children_[i]['obj']; + End + else + a[ length(a) ] := children_[i]; + end; + children_ := a; + End; + End; + End; + + Function GetAttrsEx(); + Begin + return GetAttrs();//暂时没有发现需要更新属性前缀的情况 + if not istable(ReplaceArr) then return GetAttrs(); + attr := GetAttrs(); + for i:=0 to length(attr)-1 do + attr[i][1] := ReplaceName(attr[i][1]); + return attr; + End + +private + Function replaceNodeName(); + Begin + for k, v in ReplaceArr do + 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 diff --git a/funcext/TSOffice/TSXlsxFile.tsf b/funcext/TSOffice/TSXlsxFile.tsf index e7d9566..f28ff72 100644 --- a/funcext/TSOffice/TSXlsxFile.tsf +++ b/funcext/TSOffice/TSXlsxFile.tsf @@ -1,4 +1,4 @@ -// Version 1.8.5 +// Version 1.8.6 Type TSXlsxFile = Class ///Version: V1.0 2022-08-08 ///适用于 Microsoft Excel? 2007 及以上版本创建的电子表格文档。支持 XLSX / XLSM / XLTM / XLTX 等多种文档格式。 @@ -344,7 +344,7 @@ Type TSXlsxFile = Class [err, cell] := CoordinatesToCellName(colNum + j, rowNum + i); j++; ret := SetCellValue(sheet, cell, v); - if not ret then return array(1, "error") + if not ret then return array(1, "error"); End; End; return array(0, "OK"); diff --git a/更新日志.md b/更新日志.md index 58ebb61..b8d5345 100644 --- a/更新日志.md +++ b/更新日志.md @@ -1,7 +1,19 @@ # 更新日志 +## 2026-01-16 + +#### V1.8.6 + +修复语法问题 + +#### word + +1. 修复`InsertTable`多行数据插入缺失问题 + ## 2025-12-15 +#### V1.8.5 + #### word 1. 修复插入word时,单元格内容不完整问题