Restore imperfect array formula values in xlsx writer
oleibman said:
The results of uncommenting the statements will often not be successful.
In Excel, if I enter `=MINVERSE({2,0;0,1})` into cell A1, you will get a
`dynamic array` (which we do not yet support) - A1 will contain 0.5, A2
and B1 will contain 0, and B2 will contain 1. There are also `spill`
implications for such a formula. The XML for these cells will be:
``` xml
<row r="1" spans="1:2" x14ac:dyDescent="0.3">
<c r="A1" cm="1">
<f t="array" ref="A1:B2">MINVERSE({2,0;0,1})</f>
<v>0.5</v>
</c>
<c r="B1">
<v>0</v>
</c>
</row>
<row r="2" spans="1:2" x14ac:dyDescent="0.3">
<c r="A2">
<v>0</v>
</c>
<c r="B2">
<v>1</v>
</c>
</row>
```
I believe that the PhpSpreadsheet equivalent of doing this (with the statements
uncommented) is:
```php
$spreadsheet = new Spreadsheet();
$calculation = Calculation::getInstance($spreadsheet);
$calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_ARRAY);
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('A1')->setValue('=MINVERSE({2,0;0,1})');
$writer = new Xlsx($spreadsheet);
$oufil = 'issue.2343.xlsx';
$writer->save($oufil);
```
But our output file only fills in A1:
```xml
<row r="1" spans="1:1">
<c r="A1">
<f>MINVERSE({2,0;0,1})</f>
<v>0.5</v>
</c>
</row>
```
And, even though A1 has its correct value, note that its `f` tag does not have
a `t` attribute. This is because we never set any formula attributes, except
in Xlsx Reader (see next paragraph), so we do not encounter the `'array'`
condtion for a formula newly added to a spreadsheet.
We do slightly better when we read the first file (as opposed to creating a new
spreadsheet), but we succeed only by accident. Because B1, A2, and B2 are
assigned values in the XML, all 4 cells will have the expected values. But they
are now independent of each other, not part of a dynamic array. When we write
this out, it is almost correct:
```xml
<row r="1" spans="1:2">
<c r="A1">
<f>MINVERSE({2,0;0,1})</f>
<v>0.5</v>
</c>
<c r="B1">
<v>0</v>
</c>
</row>
<row r="2" spans="1:2">
<c r="A2">
<v>0</v>
</c>
<c r="B2">
<v>1</v>
</c>
</row>
```
Again, the `f` tag has no `t` attribute, and it doesn't seem to matter whether we set
RETURN_TYPE_ARRAY or not. I think this particular aspect of the problem might be
relatively easy to fix.
This commit is contained in:
parent
0c93bbaaa3
commit
a2be574f36
|
|
@ -1205,27 +1205,26 @@ class Worksheet extends WriterPart
|
|||
$objWriter->writeAttribute('t', 'b');
|
||||
$calculatedValue = (int) $calculatedValue;
|
||||
}
|
||||
// array values are not yet supported
|
||||
//$attributes = $pCell->getFormulaAttributes();
|
||||
//if (($attributes['t'] ?? null) === 'array') {
|
||||
// $objWriter->startElement('f');
|
||||
// $objWriter->writeAttribute('t', 'array');
|
||||
// $objWriter->writeAttribute('ref', $pCellAddress);
|
||||
// $objWriter->writeAttribute('aca', '1');
|
||||
// $objWriter->writeAttribute('ca', '1');
|
||||
// $objWriter->text(substr($cellValue, 1));
|
||||
// $objWriter->endElement();
|
||||
//} else {
|
||||
// $objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
|
||||
//}
|
||||
$objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
|
||||
self::writeElementIf(
|
||||
$objWriter,
|
||||
$this->getParentWriter()->getOffice2003Compatibility() === false,
|
||||
'v',
|
||||
($this->getParentWriter()->getPreCalculateFormulas() && !is_array($calculatedValue) && substr($calculatedValue ?? '', 0, 1) !== '#')
|
||||
? StringHelper::formatNumber($calculatedValue) : '0'
|
||||
);
|
||||
|
||||
$attributes = $cell->getFormulaAttributes();
|
||||
if (($attributes['t'] ?? null) === 'array') {
|
||||
$objWriter->startElement('f');
|
||||
$objWriter->writeAttribute('t', 'array');
|
||||
$objWriter->writeAttribute('ref', $cell->getCoordinate());
|
||||
$objWriter->writeAttribute('aca', '1');
|
||||
$objWriter->writeAttribute('ca', '1');
|
||||
$objWriter->text(substr($cellValue, 1));
|
||||
$objWriter->endElement();
|
||||
} else {
|
||||
$objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
|
||||
self::writeElementIf(
|
||||
$objWriter,
|
||||
$this->getParentWriter()->getOffice2003Compatibility() === false,
|
||||
'v',
|
||||
($this->getParentWriter()->getPreCalculateFormulas() && !is_array($calculatedValue) && substr($calculatedValue, 0, 1) !== '#')
|
||||
? StringHelper::formatNumber($calculatedValue) : '0'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue