Type TSWdRange = Class public Function Create(rootNode, startP, endP);overload; Function Create(rootNode, targetNode);overload; Function Init(); Function Operator[](index); Function Run(); Function Refresh(); Function GetStart(); Function GetEnd(); Function SplitRun();overload; Function SplitRun(index);overload; Function Clear(deleteAll); Function Size(); Function Print(); Begin println("data = {}", data_); End; private Function FindRangeByPosition(startNode); Function FindRangeByNode(startNode); Function AddEntirety(len, node); Function AddRunInfo(runNode, tParagraph); Function AddRunInfo2(runNode, tParagraph); Function ParagraphRange(node); Function CalcPosition(startNode); public data_; // 管理range结构的数组,字段如下 // lsplit: 左边丢弃的字符数 // rsplit: 右边丢弃的字符数 // tparagraph: TOfficeObj("TParagraph")对象 // trun: TOfficeObj("TRun")对象 // text: 文本内容 // entirety: 是否是完整的段落/表格/单元格 // -- 以便在对range操作时候知道操作一个段落还是一个run,比如range.shading range.Border private start_position_; // 开始位置 end_position_; // 结束位置, 开始与结束遵循左闭右开原则 cur_position_; // 当前位置 root_node_; // 根节点 target_node_; // 目标节点,使用paragraph.Range,table.Range, cell.Range时用 split_flag_; // 切割标志 proxy_; // 代理类,提供外部对数组data_的读写 End; Type Proxy = Class public Function Create(obj); property TRun read ReadTRun write WriteTRun; property TParagraph read ReadTParagraph write WriteTParagraph; property Entirety read ReadEntirety write WriteEntirety; Function WriteEntirety(value); Function ReadEntirety(); Function WriteTParagraph(value); Function ReadTParagraph(); Function WriteTRun(value); Function ReadTRun(); [weakref]obj_; index_; End; Function Proxy.Create(obj); Begin obj_ := obj; index_ := nil; End; Function Proxy.WriteEntirety(value); Begin obj_.data_[index_]["entirety"] := value; End; Function Proxy.ReadEntirety(); Begin return obj_.data_[index_]["entirety"]; End; Function Proxy.WriteTParagraph(value); Begin obj_.data_[index_]["tparagraph"] := value; End; Function Proxy.ReadTParagraph(); Begin return obj_.data_[index_]["tparagraph"]; End; Function Proxy.WriteTRun(value); Begin obj_.data_[index_]["trun"] := value; End; Function Proxy.ReadTRun(); Begin return obj_.data_[index_]["trun"]; End; // TSWdRange实现 Function TSWdRange.Create(rootNode, startP, endP);overload; Begin root_node_ := rootNode; start_position_ := startP; end_position_ := endP = -1 ? INF : endP; target_node_ := nil; self.Init(); End; Function TSWdRange.Create(rootNode, targetNode);overload; Begin root_node_ := rootNode; target_node_ := targetNode; start_position_ := nil; end_position_ := nil; self.Init(); End; Function TSWdRange.Init(); Begin cur_position_ := 0; split_flag_ := false; data_ := array(); self.Run(); proxy_ := new Proxy(self); End; Function Operator TSWdRange.[](index); Begin proxy_.index_ := index; return proxy_; End; Function TSWdRange.Run(); Begin if target_node_ then self.FindRangeByNode(target_node_); else self.FindRangeByPosition(root_node_); End; Function TSWdRange.Refresh(); Begin if target_node_ then self.FindRangeByNode(target_node_); End; Function TSWdRange.Size(); Begin return length(data_); End; Function TSWdRange.GetStart(); Begin if ifnil(start_position_) then self.CalcPosition(root_node_); return start_position_; End; Function TSWdRange.GetEnd(); Begin if ifnil(end_position_) then self.CalcPosition(root_node_); return end_position_; End; Function TSWdRange.SplitRun();overload; Begin if split_flag_ then return; for i:=0 to length(data_)-1 do self.SplitRun(i); split_flag_ := true; End; Function TSWdRange.SplitRun(index);overload; Begin if ifnil(data_[index]["lsplit"]) and ifnil(data_[index]["rsplit"]) then return data_[index]; paragraph := data_[index]["tparagraph"]; run := data_[index]["trun"]; text := data_[index]["text"]; if data_[index]["lsplit"] then // 分割左边 begin lpos := data_[index]["lsplit"]; run.SetText(AnsiToUtf8(leftstr(text, lpos))); new_run := paragraph.AppendRun(run); new_run.CopyFontFormat(run); text := rightstr(text, lengthw(text)-lpos); new_run.SetText(AnsiToUtf8(text)); data_[index]["text"] := text; data_[index]["lsplit"] := nil; run := new_run; end if data_[index]["rsplit"] then // 分割右边的run begin rpos := data_[index]["rsplit"]; new_run := paragraph.AppendRun(run); new_run.CopyFontFormat(run); new_run.SetText(AnsiToUtf8(rightstr(text, rpos))); new_text := AnsiToUtf8(leftstr(text, lengthw(text) - rpos)); run.SetText(new_text); data_[index]["rsplit"] := nil; data_[index]["text"] := new_text; end data_[index]["trun"] := run; End; Function TSWdRange.Clear(deleteAll); Begin self.SplitRun(); arr := array(); first := data_[0]; para := first["tparagraph"]; if deleteAll then arr[length(arr)] := para.Root(); for i:=1 to length(data_)-1 do begin if data_[i]["tparagraph"] <> para then begin arr[length(arr)] := data_[i]["tparagraph"].Root(); end else begin p := data_[i]["tparagraph"]; r := data_[i]["trun"]; if ifObj(r.Root()) then p.Root().DeleteChild(r.Root()); end end first["trun"].ClearText(); data_ := array(); if not deleteAll then data_[0] := first; 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 self.AddRunInfo(nil, paragraph_obj); end else begin sub_node := node.FirstChildElement(); while ifObj(sub_node) do begin case sub_node.GetName() of "w:r": begin self.AddRunInfo(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 self.AddRunInfo(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 := self.FindRangeByPosition(tc); if flag then return 1; if cur_position_ >= end_position_ then return 1; self.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; self.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(runNode, tParagraph); Begin run_obj := TOfficeObj("TRun"); run_obj.Init(runNode); text := ifObj(runNode) ? run_obj.Text() : ""; if class(TSXml).IsUtf8() then text := Utf8ToAnsi(text); len := text ? lengthw(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; // 左边切割,左边丢弃的字符数 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 self.FindRangeByNode(node); node := node.NextElement(); end end case startNode.GetName() of "w:p": self.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.CalcPosition(startNode); Begin node := startNode.FirstChildElement(); while ifObj(node) do begin if node.Eq(target_node_) then begin eq_flag := true; start_position_ := cur_position_; end case node.GetName() of "w:p": begin paragraph_obj := TOfficeObj("TParagraph"); paragraph_obj.Init(node); if paragraph_obj.Empty() then // 空段落 begin cur_position_ += 1; end else begin sub_node := node.FirstChildElement(); while ifObj(sub_node) do begin case sub_node.GetName() of "w:r": begin run_obj := TOfficeObj("TRun"); run_obj.Init(sub_node); text := run_obj.Text(); if class(TSXml).IsUtf8() then text := Utf8ToAnsi(text); cur_position_ += lengthw(text); end "w:ins", "w:del": begin run_node := sub_node.FirstChildElement("w:r"); while ifObj(run_node) do begin run_obj := TOfficeObj("TRun"); run_obj.Init(run_node); text := run_obj.Text(); if class(TSXml).IsUtf8() then text := Utf8ToAnsi(text); cur_position_ += lengthw(text); 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 flag := self.CalcPosition(tc); if flag then return 1; tc := tc.NextElement("w:tc"); end cur_position_ += 1; tr := tr.NextElement("w:tr"); end end end; if eq_flag then begin end_position_ := cur_position_; return 1; end node := node.NextElement(); end End; Function TSWdRange.ParagraphRange(node); Begin paragraph_obj := TOfficeObj("TParagraph"); paragraph_obj.Init(node); if paragraph_obj.Empty() then begin self.AddRunInfo2(nil, paragraph_obj); end else begin sub_node := node.FirstChildElement(); while ifObj(sub_node) do begin case sub_node.GetName() of "w:r": self.AddRunInfo2(sub_node, paragraph_obj); "w:ins", "w:del": begin run_node := sub_node.FirstChildElement("w:r"); while ifObj(run_node) do begin self.AddRunInfo2(run_node, paragraph_obj); run_node := run_node.NextElement("w:r"); end end end; sub_node := sub_node.NextElement(); end end End; Function TSWdRange.AddRunInfo2(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]["entirety"] := target_node_; End;