Skip to content

Instantly share code, notes, and snippets.

@SmiSoft
Created April 27, 2021 20:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SmiSoft/5e14de917d2913795d813112e60c274c to your computer and use it in GitHub Desktop.
Save SmiSoft/5e14de917d2913795d813112e60c274c to your computer and use it in GitHub Desktop.
ODT/ODS import/export for Lazarus (no LibreOffice installed required)
unit OdtImport;
interface
uses
Classes, OdtFilter, OdtExport, laz2_Dom;
Type
{ TOdtImport }
TOdtImport=class(TOdtProcess)
protected
fTableName:string;
fTableData:PStringMatrix;
fContains:boolean;
// преобразует значение ячейки из таблицы текстовое представление
// в отличии от стандартного TextContent, сохраняет разбиение по абзацам
function ProcessTableCell(Cell:TDOMNode):string;
procedure ProcessTableRow(Row:TDOMNodeList;out RowData:TStringVector);
procedure ProcessContent({%H-}Doc:TXMLDocument);override;
public
class procedure FromFile(const Input,TableName:string;out TableData:TStringMatrix);
class function ContainsTable(const Input,TableName:string):boolean;
end;
implementation
{ TOdtImport }
function TOdtImport.ProcessTableCell(Cell: TDOMNode): string;
var
Par:TDOMNode;
begin
Result:='';
For Par in Cell.GetEnumeratorAllChildren do begin
if String(Par.NodeName)<>'text:p' then continue;
if Result='' then
Result:=String(Par.TextContent)
else
Result:=Result+#13#10+String(Par.TextContent);
end;
end;
procedure TOdtImport.ProcessTableRow(Row: TDOMNodeList; out RowData:TStringVector);
var
I,Cnt:integer;
Node:TDOMNode;
begin
// считаем количество ячеек в данном ряду. Подстраховываемся на случай, если
// в ряду окажутся не только ячейки, из документации это не 100% следует
Cnt:=0;
For I:=0 to Row.Count-1 do begin
Node:=Row.Item[I];
if String(Node.NodeName)<>'table:table-cell' then continue;
Inc(Cnt);
end;
SetLength(RowData,Cnt);
// производим заполнение данными из ячеек
Cnt:=0;
For I:=0 to Row.Count-1 do begin
Node:=Row.Item[I];
if String(Node.NodeName)<>'table:table-cell' then continue;
RowData[Cnt]:=ProcessTableCell(Node);
Inc(Cnt);
end;
end;
procedure TOdtImport.ProcessContent(Doc: TXMLDocument);
var
Tables,Rows:TDOMNodeList;
Node,TableName:TDOMNode;
Attr:TDOMNamedNodeMap;
I,J,K:integer;
begin
Tables:=Doc.GetElementsByTagName('table:table');
For I:=0 to Tables.Count-1 do begin
Node:=Tables.Item[I];
Attr:=Node.Attributes;
if Attr=nil then continue;
TableName:=Attr.GetNamedItem('table:name');
if TableName=nil then continue;
if String(TableName.NodeValue)<>fTableName then continue;
// мы находимся в таблице, имя которой нас интересует
fContains:=true;
if fTableData<>nil then begin
Rows:=Node.ChildNodes;
For J:=0 to Rows.Count-1 do begin
Node:=Rows.Item[J];
if String(Node.NodeName)<>'table:table-row' then continue;
K:=Length(fTableData^);
SetLength(fTableData^,K+1);
ProcessTableRow(Node.ChildNodes,fTableData^[K]);
end;
end;
exit;
end;
inherited ProcessContent(Doc);
end;
class procedure TOdtImport.FromFile(const Input, TableName: string; out TableData: TStringMatrix);
var
Iam:TOdtImport;
begin
Iam:=TOdtImport.Create;
try
Iam.fTableData:=@TableData;
Iam.fTableName:=TableName;
Iam.Process(Input);
finally
Iam.Free;
end;
end;
class function TOdtImport.ContainsTable(const Input, TableName: string): boolean;
var
Iam:TOdtImport;
begin
Iam:=TOdtImport.Create;
try
Iam.fTableName:=TableName;
Iam.Process(Input);
Result:=Iam.fContains;
finally
Iam.Free;
end;
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment