Type TSWdRange = Class public Function Create(rootNode, startP, endP);overload; Function Create(rootNode, targetNode);overload; Function Init(); Function Run(); Function GetStart(); Function GetEnd(); Function SplitRun();overload; Function SplitRun(arr);overload; Function Clear(); Function Print(); public Data; // 管理range结构的数组,字段如下 // lsplit: 左边丢弃的字符数 // rsplit: 右边丢弃的字符数 // tparagraph: TOfficeObj("TParagraph")对象 // trun: TOfficeObj("TRun")对象 // text: 文本内容 // root: 根节点 // parent: 父节点 // entirety: 是否是完整的段落/表格/单元格 private Function FindRangeByPosition(startNode); Function FindRangeByNode(startNode); Function AddEntirety(len, node); Function AddRunInfo(parentNode, runNode, tParagraph); Function AddRunInfo2(parentNode, runNode, tParagraph); Function ParagraphRange(node); private start_position_; // 开始位置 end_position_; // 结束位置, 开始与结束遵循左闭右开原则 cur_position_; // 当前位置 root_node_; // 根节点 target_node_; // 目标节点,使用paragraph.Range,table.Range, cell.Range时用 split_flag_; // 切割标志 End; Function TSWdRange.Create(rootNode, startP, endP);overload; Begin root_node_ := rootNode; start_position_ := startP; end_position_ := endP; targetNode := nil; Init(); End; Function TSWdRange.Create(rootNode, targetNode);overload; Begin root_node_ := rootNode; target_node_ := targetNode; start_position_ := nil; end_position_ := nil; Init(); End; Function TSWdRange.Init(); Begin cur_position_ := 0; split_flag_ := false; Data := array(); Run(); End; Function TSWdRange.Run(); Begin if target_node_ then FindRangeByNode(target_node_); else FindRangeByPosition(root_node_); End; Function TSWdRange.Print(); Begin println("print... {}", Data); End; Function TSWdRange.GetStart(); Begin if ifnil(start_position_) then return 0; return start_position_; End; Function TSWdRange.GetEnd(); Begin if ifnil(end_position_) then return 0; return end_position_; End; Function TSWdRange.SplitRun();overload; Begin if split_flag_ then return; for i:=0 to length(Data)-1 do Data[i] := SplitRun(Data[i]); split_flag_ := true; End; Function TSWdRange.SplitRun(arr);overload; Begin insert_run := function(root, node); begin new_node := root.InsertAfterChild(node, "element", "w:r"); run := TOfficeObj("TRun"); run.Init(new_node); return run; end if ifnil(arr["lsplit"]) and ifnil(arr["rsplit"]) then return arr; paragraph := arr["tparagraph"]; run := arr["trun"]; text := arr["text"]; if arr["lsplit"] then // 分割左边 begin lpos := arr["lsplit"]; run.SetText(text[:lpos]); run := ##insert_run(paragraph.Root(), run.Root()); text := text[lpos + 1:]; run.SetText(text); arr["text"] := text; arr["lsplit"] := nil; end if arr["rsplit"] then // 分割右边的run begin rpos := length(text) - arr["rsplit"]; run.SetText(text[1:rpos]); new_run := ##insert_run(paragraph.Root(), run.Root()); new_run.SetText(text[rpos+1:]); arr["rsplit"] := nil; arr["text"] := text[1:rpos]; end arr["trun"] := run; return arr; End; Function TSWdRange.FindRangeByPosition(startNode); Begin node := startNode.FirstChildElement(); while ifObj(node) do begin len := length(Data); // 标记完整段落/表格的起始位置 case node.GetName() of "w:p": begin paragraph_obj := TOfficeObj("TParagraph"); paragraph_obj.Init(node); if paragraph_obj.Empty() then // 空段落 begin AddRunInfo(startNode, nil, paragraph_obj); end else begin sub_node := node.FirstChildElement(); while ifObj(sub_node) do begin case sub_node.GetName() of "w:r": begin AddRunInfo(startNode, sub_node, paragraph_obj); if cur_position_ >= end_position_ then return 1; end "w:ins", "w:del": begin run_node := sub_node.FirstChildElement("w:r"); while ifObj(run_node) do begin AddRunInfo(startNode, run_node, paragraph_obj); if cur_position_ >= end_position_ then return 1; run_node := run_node.NextElement("w:r"); end end end; sub_node := sub_node.NextElement(); end // 完整段落 cur_position_ += 1; end end "w:tbl": begin tr := node.FirstChildElement("w:tr"); while ifObj(tr) do begin tc := tr.FirstChildElement("w:tc"); while ifObj(tc) do begin cell_len := length(Data); flag := FindRangeByPosition(tc); if flag then return 1; if cur_position_ >= end_position_ then return 1; AddEntirety(cell_len, tc); tc := tc.NextElement("w:tc"); end cur_position_ += 1; if cur_position_ >= end_position_ then return 1; tr := tr.NextElement("w:tr"); end end end; AddEntirety(len, node); if cur_position_ >= end_position_ then return 1; node := node.NextElement(); end End; Function TSWdRange.AddEntirety(len, node); Begin for i:=len to length(Data)-1 do Data[i]["entirety"] := node; End; Function TSWdRange.AddRunInfo(parentNode, runNode, tParagraph); Begin run_obj := TOfficeObj("TRun"); run_obj.Init(runNode); text := ifObj(runNode) ? run_obj.Text() : ""; len := text ? length(text) : 1; if cur_position_ + len > start_position_ then begin length := length(Data); Data[length]["tparagraph"] := tparagraph; Data[length]["trun"] := run_obj; Data[length]["text"] := text; Data[length]["root"] := root_node_; Data[length]["parent"] := parentNode; // 左边切割,左边丢弃的字符数 if cur_position_ < start_position_ and cur_position_ + len > start_position_ + 1 then Data[length]["lsplit"] := start_position_ - cur_position_; // 右边切割,右边丢弃的字符数 if cur_position_ + len > end_position_ then Data[length]["rsplit"] := cur_position_ + len - end_position_; end cur_position_ += len; End; Function TSWdRange.FindRangeByNode(startNode); Begin tc_pf := function(tc); begin node := tc.FirstChildElement(); while ifObj(node) do begin FindRangeByNode(node); node := node.NextElement(); end end case startNode.GetName() of "w:p": ParagraphRange(startNode); "w:tbl": begin tr := startNode.FirstChildElement("w:tr"); while ifObj(tr) do begin tc := tr.FirstChildElement("w:tc"); while ifObj(tc) do begin ##tc_pf(tc); tc := tc.NextElement("w:tc"); end tr := tr.NextElement("w:tr"); end end "w:tc": begin ##tc_pf(startNode); end end; End; Function TSWdRange.ParagraphRange(node); Begin paragraph_obj := TOfficeObj("TParagraph"); paragraph_obj.Init(node); if paragraph_obj.Empty() then begin AddRunInfo2(nil, nil, paragraph_obj); end else begin sub_node := node.FirstChildElement(); while ifObj(sub_node) do begin case sub_node.GetName() of "w:r": AddRunInfo2(nil, sub_node, paragraph_obj); "w:ins", "w:del": begin run_node := sub_node.FirstChildElement("w:r"); while ifObj(run_node) do begin AddRunInfo2(nil, run_obj, paragraph_obj); run_node := run_node.NextElement("w:r"); end end end; sub_node := sub_node.NextElement(); end end End; Function TSWdRange.AddRunInfo2(parentNode, runNode, tParagraph); Begin run_obj := TOfficeObj("TRun"); run_obj.Init(runNode); length := length(Data); Data[length]["tparagraph"] := tParagraph; Data[length]["trun"] := run_obj; Data[length]["root"] := root_node_; Data[length]["parent"] := parentNode; Data[length]["entirety"] := target_node_; End; Function TSWdRange.Clear(); Begin SplitRun(); first := Data[0]; para := first["tparagraph"]; index := 0; for i:=1 to length(Data)-1 do begin if Data[i]["tparagraph"] <> para then begin parent := Data[i]["parent"]; parent.DeleteChild(Data[i]["tparagraph"].Root()); end else begin p := Data[i]["tparagraph"]; r := Data[i]["trun"]; if ifObj(p.Root()) and ifObj(r.Root()) then p.Root().DeleteChild(r.Root()); end end Data := array(); Data[0] := first; End;