fpspreadsheet: Fix reading of defined names in ods (use correct xml attributes)

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9410 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-08-01 11:08:30 +00:00
parent 12ee2c0b1b
commit 0269bdceff
5 changed files with 87 additions and 45 deletions

View File

@ -1,5 +1,4 @@
program demo_read_definednames;
{$DEFINE ODS}
uses
SysUtils, fpspreadsheet, fpsTypes, fpsClasses, fpsUtils, fpsAllFormats;
var
@ -8,14 +7,17 @@ var
cell: PCell;
i, j: Integer;
fn: String;
fmt: TsSpreadsheetFormat = sfOpendocument;
// fmt: TsSpreadsheetFormat = xlsxOOXML;
begin
{$IFDEF ODS}
fn := 'test_defnames.ods';
{$ELSE}
fn := 'test_defnames.xlsx';
{$ENDIF}
fn := 'Mappe2.ods';
fn := 'test_defnames';
fn := 'Mappe_illegalRef';
fn := 'Mappe3';
case fmt of
sfOpenDocument: fn := fn + '.ods';
sfOOXML: fn := fn + '.xlsx';
else raise Exception.Create('Format not supported:');
end;
wb := TsWorkbook.Create;
try
@ -28,9 +30,9 @@ begin
for i := 0 to wb.DefinedNames.Count-1 do
begin
Write(' "', wb.DefinedNames[i].Name, '" --> ');
case ExtractFileExt(fn) of
'.xlsx': WriteLn(wb.DefinedNames[i].RangeAsString(wb));
'.ods': WriteLn(wb.DefinedNames[i].RangeAsString_ODS(wb));
case fmt of
sfOOXML: WriteLn(wb.DefinedNames[i].RangeAsString(wb));
sfOpenDocument: WriteLn(wb.DefinedNames[i].RangeAsString_ODS(wb));
end;
end;

View File

@ -68,6 +68,17 @@ begin
{----------}
// Defined name with illegal reference
ws := wb.AddWorksheet('Illegal Ref');
wsIdx1 := wb.GetWorksheetIndex(ws);
ws.WriteText(0, 0, 'aaa');
ws.WriteNumber(1, 0, 123);
ws.DefinedNames.Add('aaa', wsIdx1, wsIdx1, 1,0, 1,0);
ws.DeleteRow(1); // Delete the named cell --> should be #REF! now.
ws.WriteFormula(2, 0, '=aaa'); // Should be #REF!
{----------}
wb.WriteToFile('test_defnames.xlsx', true);
wb.WriteToFile('test_defnames.ods', true);
finally

View File

@ -1886,13 +1886,14 @@ begin
sh1 := book.GetWorksheetByIndex(Sheet1);
if IllegalRef then
begin
Result := Format('$%s!%s', [sh1.Name, STR_ERR_ILLEGAL_REF]); // Is '!' correct?
Result := Format('$%s.%s', [sh1.Name, STR_ERR_ILLEGAL_REF]); // Is '!' correct?
exit;
end;
Result := Format('$%s.%s', [sh1.Name, GetCellString(Row1, Col1, [])]);
if (Sheet1 <> Sheet2) or (Row1 <> Row2) or (Col1 <> Col2) then
begin
sh2 := book.GetWorksheetByIndex(Sheet2);
if sh2 = nil then sh2 := sh1;
Result := Format('%s:$%s.%s', [Result, sh2.Name, GetCellString(Row2, Col2, [])]);
end;
end;

View File

@ -2643,12 +2643,23 @@ var
defName: String;
defAddr: String;
defExpr: String;
defBaseAddr: String;
r1, c1, r2, c2: Cardinal;
sheetName1, sheetName2: String;
sheetIdx1, sheetIdx2: Integer;
sheetIdx1, sheetIdx2, p: Integer;
flags: TsRelFlags;
err: TsErrorValue;
isDefName: Boolean;
procedure ErrorRange(ASheetName: String);
begin
sheetName1 := ASheetName;
sheetName2 := ASheetName;
r1 := UNASSIGNED_ROW_COL_INDEX;
c1 := UNASSIGNED_ROW_COL_INDEX;
r2 := UNASSIGNED_ROW_COL_INDEX;
c2 := UNASSIGNED_ROW_COL_INDEX;
end;
begin
if ANode = nil then
exit;
@ -2663,37 +2674,43 @@ begin
while ANode <> nil do
begin
nodeName := ANode.NodeName;
if nodeName = 'table:named-expression' then
if (nodeName = 'table:named-range') or (nodeName = 'table:named-expression') then
begin
defName := GetAttrValue(ANode, 'table:name');
defAddr := GetAttrValue(ANode, 'table:cell-range-address');
defBaseAddr := GetAttrValue(ANode, 'table:base-cell-address');
defExpr := GetAttrValue(ANode, 'table:expression');
if TryStrToErrorValue(defExpr, '!', sheetName1, err) then // not clear whether '!' is correct; test file was created from Excel
if TryStrToErrorValue(defAddr, err) and (err <> errOK) then
begin
r1 := UNASSIGNED_ROW_COL_INDEX;
c1 := UNASSIGNED_ROW_COL_INDEX;
r2 := UNASSIGNED_ROW_COL_INDEX;
c2 := UNASSIGNED_ROW_COL_INDEX;
sheetName2 := sheetName1;
isDefName := true;
p := pos('.', defBaseAddr);
if p > 0 then
sheetName1 := Copy(defBaseAddr, 1, p-1)
else
sheetName1 := book.GetFirstWorksheet.Name;
ErrorRange(sheetName1);
end else
if (TryStrToErrorValue(defExpr, '!', sheetName1, err) or
TryStrToErrorValue(defExpr, '.', sheetName2, err)) and
(err <> errOK) then // not clear whether '!' is correct; test file was created from Excel
begin
ErrorRange(sheetName1);
end else
if TryStrToCellRange_ODS(defAddr, sheetName1, sheetName2, r1, c1, r2, c2, flags) then
isDefName := true
else
isDefName := false;
if isDefName then
begin
if (sheetName1 <> '') and (sheetName1[1] = '$') then Delete(sheetName1, 1,1);
if (sheetName2 <> '') and (sheetName2[1] = '$') then Delete(sheetName2, 1,1);
sheetIdx1 := book.GetWorksheetIndex(sheetName1);
sheetIdx2 := book.GetWorksheetIndex(sheetName2);
if AWorksheet = nil then
// global defined names
book.DefinedNames.Add(defName, sheetIdx1, sheetIdx2, r1, c1, r2, c2)
else
// local defined names
TsWorksheet(AWorksheet).DefinedNames.Add(defName, sheetIdx1, sheetIdx2, r1, c1, r2, c2);
end;
;
end else
Continue;
if (sheetName1 <> '') and (sheetName1[1] = '$') then Delete(sheetName1, 1,1);
if (sheetName2 <> '') and (sheetName2[1] = '$') then Delete(sheetName2, 1,1);
sheetIdx1 := book.GetWorksheetIndex(sheetName1);
sheetIdx2 := book.GetWorksheetIndex(sheetName2);
if AWorksheet = nil then
// global defined names
book.DefinedNames.Add(defName, sheetIdx1, sheetIdx2, r1, c1, r2, c2)
else
// local defined names
TsWorksheet(AWorksheet).DefinedNames.Add(defName, sheetIdx1, sheetIdx2, r1, c1, r2, c2);
end;
ANode := ANode.NextSibling;
end;
@ -8813,13 +8830,22 @@ begin
sheet1 := book.GetWorksheetByIndex(ADefinedName.Range.Sheet1);
sheet2 := book.GetWorksheetByIndex(ADefinedName.Range.Sheet2);
Result := Format(
'<table:named-range ' +
'table:name="%s" ' +
'table:base-cell-address="$%s.$A$1" ' +
'table:cell-range-address="%s" />',
[ ADefinedName.Name, sheet1.Name, ADefinedName.RangeAsString_ODS(FWorkbook) ]
);
if ADefinedName.IllegalRef then
Result := Format(
'<table:named-expression '+
'table:name="%s" ' +
// 'table:base-cell-address="$%s.$A$1" ' +
'table:expression="$%s.#REF!" />',
[ ADefinedName.Name, {sheet1.Name, }sheet1.Name ]
)
else
Result := Format(
'<table:named-range ' +
'table:name="%s" ' +
// 'table:base-cell-address="$%s.$A$1" ' + // needed when we support relative defined names.
'table:cell-range-address="%s" />',
[ ADefinedName.Name, {sheet1.Name, }ADefinedName.RangeAsString_ODS(FWorkbook) ]
);
end;
procedure TsSpreadOpenDocWriter.WriteError(AStream: TStream;

View File

@ -1365,6 +1365,8 @@ begin
begin
cell1str := Copy(AStr, 1, p-1);
cell2Str := Copy(AStr, p+1, MaxInt);
if (cell2Str <> '') and (cell2Str[1] = '.') then
System.Delete(cell2str, 1, 1);
end;
p := pos('.', cell1Str);
@ -3022,7 +3024,7 @@ function Range3D(ASheetIdx1, ASheetIdx2: Integer;
var
rng: TsCellRange;
begin
rng := Range(ARow1, ACol1, ARow2, ACol2);
rng := Range(ARow1, ACol1, ARow2, ACol2); // Make sure that the indices are ordered.
Result.Row1 := rng.Row1;
Result.Col1 := rng.Col1;
Result.Row2 := rng.Row2;