You've already forked lazarus-ccr
fpspreadsheet: Improved detection of space separators in date/time formats. Generally valid, no modification of xmlread required. Side-effect: leading spaces of xml elements have to be skipped manually
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3122 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -19,9 +19,6 @@ http://docs.oasis-open.org/office/v1.1/OS/OpenDocument-v1.1.pdf
|
|||||||
AUTHORS: Felipe Monteiro de Carvalho / Jose Luis Jurado Rincon
|
AUTHORS: Felipe Monteiro de Carvalho / Jose Luis Jurado Rincon
|
||||||
}
|
}
|
||||||
|
|
||||||
{ TODO: Remove the date/time separator workaround in ReadNumStyle once a patch
|
|
||||||
giving access to PreserveSpaces in xmlRead is available in fpc }
|
|
||||||
|
|
||||||
|
|
||||||
unit fpsopendocument;
|
unit fpsopendocument;
|
||||||
|
|
||||||
@ -183,7 +180,7 @@ const
|
|||||||
OPENDOC_PATH_SETTINGS = 'settings.xml';
|
OPENDOC_PATH_SETTINGS = 'settings.xml';
|
||||||
OPENDOC_PATH_STYLES = 'styles.xml';
|
OPENDOC_PATH_STYLES = 'styles.xml';
|
||||||
OPENDOC_PATH_MIMETYPE = 'mimetype';
|
OPENDOC_PATH_MIMETYPE = 'mimetype';
|
||||||
OPENDOC_PATH_METAINF = 'META-INF' + '/';
|
OPENDOC_PATH_METAINF = 'META-INF' + '/';
|
||||||
OPENDOC_PATH_METAINF_MANIFEST = 'META-INF' + '/' + 'manifest.xml';
|
OPENDOC_PATH_METAINF_MANIFEST = 'META-INF' + '/' + 'manifest.xml';
|
||||||
|
|
||||||
{ OpenDocument schemas constants }
|
{ OpenDocument schemas constants }
|
||||||
@ -635,6 +632,35 @@ var
|
|||||||
FileList : TStringList;
|
FileList : TStringList;
|
||||||
BodyNode, SpreadSheetNode, TableNode: TDOMNode;
|
BodyNode, SpreadSheetNode, TableNode: TDOMNode;
|
||||||
StylesNode: TDOMNode;
|
StylesNode: TDOMNode;
|
||||||
|
|
||||||
|
{ We have to use our own ReadXMLFile procedure (there is one in xmlread)
|
||||||
|
because we have to preserve spaces in element text for date/time separator.
|
||||||
|
As a side-effect we have to skip leading spaces by ourselves. }
|
||||||
|
procedure ReadXMLFile(out ADoc: TXMLDocument; AFileName: String);
|
||||||
|
var
|
||||||
|
parser: TDOMParser;
|
||||||
|
src: TXMLInputSource;
|
||||||
|
stream: TStream;
|
||||||
|
begin
|
||||||
|
stream := TFileStream.Create(AFileName, fmOpenRead + fmShareDenyWrite);
|
||||||
|
try
|
||||||
|
parser := TDOMParser.Create;
|
||||||
|
try
|
||||||
|
parser.Options.PreserveWhiteSpace := true; // This preserves spaces!
|
||||||
|
src := TXMLInputSource.Create(stream);
|
||||||
|
try
|
||||||
|
parser.Parse(src, ADoc);
|
||||||
|
finally
|
||||||
|
src.Free;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
parser.Free;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
stream.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
//unzip content.xml into AFileName path
|
//unzip content.xml into AFileName path
|
||||||
FilePath := GetTempDir(false);
|
FilePath := GetTempDir(false);
|
||||||
@ -660,6 +686,8 @@ begin
|
|||||||
ReadNumFormats(StylesNode);
|
ReadNumFormats(StylesNode);
|
||||||
ReadStyles(StylesNode);
|
ReadStyles(StylesNode);
|
||||||
|
|
||||||
|
Doc.Free;
|
||||||
|
|
||||||
//process the content.xml file
|
//process the content.xml file
|
||||||
ReadXMLFile(Doc, FilePath+'content.xml');
|
ReadXMLFile(Doc, FilePath+'content.xml');
|
||||||
DeleteFile(FilePath+'content.xml');
|
DeleteFile(FilePath+'content.xml');
|
||||||
@ -679,6 +707,13 @@ begin
|
|||||||
//process each table (sheet)
|
//process each table (sheet)
|
||||||
TableNode := SpreadSheetNode.FindNode('table:table');
|
TableNode := SpreadSheetNode.FindNode('table:table');
|
||||||
while Assigned(TableNode) do begin
|
while Assigned(TableNode) do begin
|
||||||
|
// These nodes occur due to leading spaces which are not skipped
|
||||||
|
// automatically any more due to PreserveWhiteSpace option applied
|
||||||
|
// to ReadXMLFile
|
||||||
|
if TableNode.NodeName = '#text' then begin
|
||||||
|
TableNode := TableNode.NextSibling;
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
FWorkSheet := aData.AddWorksheet(GetAttrValue(TableNode,'table:name'));
|
FWorkSheet := aData.AddWorksheet(GetAttrValue(TableNode,'table:name'));
|
||||||
// Collect column styles used
|
// Collect column styles used
|
||||||
ReadColumns(TableNode);
|
ReadColumns(TableNode);
|
||||||
@ -690,7 +725,7 @@ begin
|
|||||||
end; //while Assigned(TableNode)
|
end; //while Assigned(TableNode)
|
||||||
|
|
||||||
finally
|
finally
|
||||||
Doc.Free;
|
if Assigned(Doc) then Doc.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -848,23 +883,25 @@ end;
|
|||||||
|
|
||||||
procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
||||||
var
|
var
|
||||||
NumFormatNode, node: TDOMNode;
|
NumFormatNode, node, childnode: TDOMNode;
|
||||||
decs: Integer;
|
decs: Integer;
|
||||||
fmtName: String;
|
fmtName: String;
|
||||||
grouping: boolean;
|
grouping: boolean;
|
||||||
fmt: String;
|
fmt: String;
|
||||||
|
numfmt_nodename, nodename: String;
|
||||||
nf: TsNumberFormat;
|
nf: TsNumberFormat;
|
||||||
nex: Integer;
|
nex: Integer;
|
||||||
s, s1, s2: String;
|
s, s1, s2: String;
|
||||||
sep: String; // separator between date/time parts
|
|
||||||
begin
|
begin
|
||||||
if not Assigned(AStylesNode) then
|
if not Assigned(AStylesNode) then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
NumFormatNode := AStylesNode.FirstChild;
|
NumFormatNode := AStylesNode.FirstChild;
|
||||||
while Assigned(NumFormatNode) do begin
|
while Assigned(NumFormatNode) do begin
|
||||||
|
numfmt_nodename := NumFormatNode.NodeName;
|
||||||
|
|
||||||
// Numbers (nfFixed, nfFixedTh, nfExp)
|
// Numbers (nfFixed, nfFixedTh, nfExp)
|
||||||
if NumFormatNode.NodeName = 'number:number-style' then begin
|
if numfmt_nodename = 'number:number-style' then begin
|
||||||
fmtName := GetAttrValue(NumFormatNode, 'style:name');
|
fmtName := GetAttrValue(NumFormatNode, 'style:name');
|
||||||
node := NumFormatNode.FindNode('number:number');
|
node := NumFormatNode.FindNode('number:number');
|
||||||
if node <> nil then begin
|
if node <> nil then begin
|
||||||
@ -890,7 +927,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end else
|
end else
|
||||||
// Percentage
|
// Percentage
|
||||||
if NumFormatNode.NodeName = 'number:percentage-style' then begin
|
if numfmt_nodename = 'number:percentage-style' then begin
|
||||||
fmtName := GetAttrValue(NumFormatNode, 'style:name');
|
fmtName := GetAttrValue(NumFormatNode, 'style:name');
|
||||||
node := NumFormatNode.FindNode('number:number');
|
node := NumFormatNode.FindNode('number:number');
|
||||||
if node <> nil then begin
|
if node <> nil then begin
|
||||||
@ -901,8 +938,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end else
|
end else
|
||||||
// Date/Time
|
// Date/Time
|
||||||
if (NumFormatNode.NodeName = 'number:date-style') or
|
if (numfmt_nodename = 'number:date-style') or (numfmt_nodename = 'number:time-style')
|
||||||
(NumFormatNode.NodeName = 'number:time-style')
|
|
||||||
then begin
|
then begin
|
||||||
fmtName := GetAttrValue(NumFormatNode, 'style:name');
|
fmtName := GetAttrValue(NumFormatNode, 'style:name');
|
||||||
fmt := '';
|
fmt := '';
|
||||||
@ -962,15 +998,9 @@ begin
|
|||||||
fmt := fmt + 'AM/PM'
|
fmt := fmt + 'AM/PM'
|
||||||
else
|
else
|
||||||
if node.NodeName = 'number:text' then begin
|
if node.NodeName = 'number:text' then begin
|
||||||
{ date/time separator workaround: sep is a space by default
|
childnode := node.FirstChild;
|
||||||
and is replaced here by the TextContent separator. It has the
|
if childnode <> nil then
|
||||||
consequence that the equivalent of the format string "yymmdd" will
|
fmt := fmt + childnode.NodeValue;
|
||||||
be decoded as "yy mm dd"!
|
|
||||||
Remove this once a patch giving access to PreserveSpaces in xmlRead
|
|
||||||
is included in fpc. }
|
|
||||||
sep := node.TextContent;
|
|
||||||
if sep = '' then sep := ' ';
|
|
||||||
fmt := fmt + sep;
|
|
||||||
end;
|
end;
|
||||||
node := node.NextSibling;
|
node := node.NextSibling;
|
||||||
end;
|
end;
|
||||||
@ -997,11 +1027,21 @@ var
|
|||||||
autoRowHeight: Boolean;
|
autoRowHeight: Boolean;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
lRow: PRow;
|
lRow: PRow;
|
||||||
|
s: String;
|
||||||
begin
|
begin
|
||||||
rowsRepeated := 0;
|
rowsRepeated := 0;
|
||||||
row := 0;
|
row := 0;
|
||||||
|
|
||||||
rowNode := ATableNode.FindNode('table:table-row');
|
rowNode := ATableNode.FindNode('table:table-row');
|
||||||
while Assigned(rowNode) do begin
|
while Assigned(rowNode) do begin
|
||||||
|
// These nodes occur due to indentation spaces which are not skipped
|
||||||
|
// automatically any more due to PreserveWhiteSpace option applied
|
||||||
|
// to ReadXMLFile
|
||||||
|
if rowNode.NodeName = '#text' then begin
|
||||||
|
rowNode := rowNode.NextSibling;
|
||||||
|
Continue;
|
||||||
|
end;
|
||||||
|
|
||||||
// Read rowstyle
|
// Read rowstyle
|
||||||
rowStyleName := GetAttrValue(rowNode, 'table:style-name');
|
rowStyleName := GetAttrValue(rowNode, 'table:style-name');
|
||||||
rowStyleIndex := FindRowStyleByName(rowStyleName);
|
rowStyleIndex := FindRowStyleByName(rowStyleName);
|
||||||
@ -1018,6 +1058,15 @@ begin
|
|||||||
//process each cell of the row
|
//process each cell of the row
|
||||||
cellNode := rowNode.FindNode('table:table-cell');
|
cellNode := rowNode.FindNode('table:table-cell');
|
||||||
while Assigned(cellNode) do begin
|
while Assigned(cellNode) do begin
|
||||||
|
|
||||||
|
// These nodes occur due to indentation spaces which are not skipped
|
||||||
|
// automatically any more due to PreserveWhiteSpace option applied
|
||||||
|
// to ReadXMLFile
|
||||||
|
if cellNode.NodeName = '#text' then begin
|
||||||
|
cellNode := cellNode.NextSibling;
|
||||||
|
Continue;
|
||||||
|
end;
|
||||||
|
|
||||||
// select this cell value's type
|
// select this cell value's type
|
||||||
paramValueType := GetAttrValue(CellNode, 'office:value-type');
|
paramValueType := GetAttrValue(CellNode, 'office:value-type');
|
||||||
paramFormula := GetAttrValue(CellNode, 'table:formula');
|
paramFormula := GetAttrValue(CellNode, 'table:formula');
|
||||||
|
Reference in New Issue
Block a user