Bugfix to ensure that General format is not treated as a date format

despite containg e for epoch
OOCalc Reader modified to process number-rows-repeated
Modify OOCalc Reader to only read cells that containing data, or merged cells
(depending on setReadDataOnly setting)
This commit is contained in:
Mark Baker 2012-07-23 21:52:14 +01:00
parent d9f9fd37f4
commit 317f00b259
3 changed files with 73 additions and 47 deletions

View File

@ -319,14 +319,23 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
foreach ($worksheetData as $key => $rowData) { foreach ($worksheetData as $key => $rowData) {
switch ($key) { switch ($key) {
case 'table-row' : case 'table-row' :
$rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
$rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ?
$rowDataTableAttributes['number-rows-repeated'] : 1;
$columnIndex = 0; $columnIndex = 0;
foreach ($rowData as $key => $cellData) { foreach ($rowData as $key => $cellData) {
$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex); $cellDataTableAttributes = $cellData->attributes($namespacesContent['table']);
++$columnIndex; $colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ?
$cellDataTableAttributes['number-columns-repeated'] : 1;
$cellDataOfficeAttributes = $cellData->attributes($namespacesContent['office']);
if (isset($cellDataOfficeAttributes['value-type'])) {
$tmpInfo['lastColumnIndex'] = max($tmpInfo['lastColumnIndex'], $columnIndex + $colRepeats - 1);
$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex + $rowRepeats);
}
$columnIndex += $colRepeats;
} }
++$rowIndex; $rowIndex += $rowRepeats;
$tmpInfo['totalRows'] = max($tmpInfo['totalRows'], $rowIndex);
break; break;
} }
} }
@ -492,6 +501,9 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
break; break;
} }
case 'table-row' : case 'table-row' :
$rowDataTableAttributes = $rowData->attributes($namespacesContent['table']);
$rowRepeats = (isset($rowDataTableAttributes['number-rows-repeated'])) ?
$rowDataTableAttributes['number-rows-repeated'] : 1;
$columnID = 'A'; $columnID = 'A';
foreach($rowData as $key => $cellData) { foreach($rowData as $key => $cellData) {
if ($this->getReadFilter() !== NULL) { if ($this->getReadFilter() !== NULL) {
@ -644,44 +656,53 @@ class PHPExcel_Reader_OOCalc implements PHPExcel_Reader_IReader
// echo 'Adjusted Formula: '.$cellDataFormula.'<br />'; // echo 'Adjusted Formula: '.$cellDataFormula.'<br />';
} }
$repeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ? $colRepeats = (isset($cellDataTableAttributes['number-columns-repeated'])) ?
$cellDataTableAttributes['number-columns-repeated'] : 1; $cellDataTableAttributes['number-columns-repeated'] : 1;
if ($type !== NULL) { if ($type !== NULL) {
for ($i = 0; $i < $repeats; ++$i) { for ($i = 0; $i < $colRepeats; ++$i) {
if ($i > 0) { if ($i > 0) {
++$columnID; ++$columnID;
} }
$objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $dataValue),$type); if ($type !== PHPExcel_Cell_DataType::TYPE_NULL) {
if ($hasCalculatedValue) { for ($rowAdjust = 0; $rowAdjust < $rowRepeats; ++$rowAdjust) {
// echo 'Forumla result is '.$dataValue.'<br />'; $rID = $rowID + $rowAdjust;
$objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->setCalculatedValue($dataValue); $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setValueExplicit((($hasCalculatedValue) ? $cellDataFormula : $dataValue),$type);
} if ($hasCalculatedValue) {
if ($formatting !== NULL) { // echo 'Forumla result is '.$dataValue.'<br />';
$objPHPExcel->getActiveSheet()->getStyle($columnID.$rowID)->getNumberFormat()->setFormatCode($formatting); $objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->setCalculatedValue($dataValue);
} }
if ($hyperlink !== NULL) { if ($formatting !== NULL) {
$objPHPExcel->getActiveSheet()->getCell($columnID.$rowID)->getHyperlink()->setUrl($hyperlink); $objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode($formatting);
} else {
$objPHPExcel->getActiveSheet()->getStyle($columnID.$rID)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_GENERAL);
}
if ($hyperlink !== NULL) {
$objPHPExcel->getActiveSheet()->getCell($columnID.$rID)->getHyperlink()->setUrl($hyperlink);
}
}
} }
} }
} }
// Merged cells // Merged cells
if ((isset($cellDataTableAttributes['number-columns-spanned'])) || (isset($cellDataTableAttributes['number-rows-spanned']))) { if ((isset($cellDataTableAttributes['number-columns-spanned'])) || (isset($cellDataTableAttributes['number-rows-spanned']))) {
$columnTo = $columnID; if (($type !== PHPExcel_Cell_DataType::TYPE_NULL) || (!$this->_readDataOnly)) {
if (isset($cellDataTableAttributes['number-columns-spanned'])) { $columnTo = $columnID;
$columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cellDataTableAttributes['number-columns-spanned'] -2); if (isset($cellDataTableAttributes['number-columns-spanned'])) {
$columnTo = PHPExcel_Cell::stringFromColumnIndex(PHPExcel_Cell::columnIndexFromString($columnID) + $cellDataTableAttributes['number-columns-spanned'] -2);
}
$rowTo = $rowID;
if (isset($cellDataTableAttributes['number-rows-spanned'])) {
$rowTo = $rowTo + $cellDataTableAttributes['number-rows-spanned'] - 1;
}
$cellRange = $columnID.$rowID.':'.$columnTo.$rowTo;
$objPHPExcel->getActiveSheet()->mergeCells($cellRange);
} }
$rowTo = $rowID;
if (isset($cellDataTableAttributes['number-rows-spanned'])) {
$rowTo = $rowTo + $cellDataTableAttributes['number-rows-spanned'] - 1;
}
$cellRange = $columnID.$rowID.':'.$columnTo.$rowTo;
$objPHPExcel->getActiveSheet()->mergeCells($cellRange);
} }
++$columnID; ++$columnID;
} }
++$rowID; $rowID += $rowRepeats;
break; break;
} }
} }

View File

@ -88,9 +88,9 @@ class PHPExcel_Shared_Date
if (($baseDate == self::CALENDAR_WINDOWS_1900) || if (($baseDate == self::CALENDAR_WINDOWS_1900) ||
($baseDate == self::CALENDAR_MAC_1904)) { ($baseDate == self::CALENDAR_MAC_1904)) {
self::$ExcelBaseDate = $baseDate; self::$ExcelBaseDate = $baseDate;
return True; return TRUE;
} }
return False; return FALSE;
} // function setExcelCalendar() } // function setExcelCalendar()
@ -166,12 +166,12 @@ class PHPExcel_Shared_Date
* *
* @param mixed $dateValue PHP serialized date/time or date object * @param mixed $dateValue PHP serialized date/time or date object
* @return mixed Excel date/time value * @return mixed Excel date/time value
* or boolean False on failure * or boolean FALSE on failure
*/ */
public static function PHPToExcel($dateValue = 0) { public static function PHPToExcel($dateValue = 0) {
$saveTimeZone = date_default_timezone_get(); $saveTimeZone = date_default_timezone_get();
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
$retValue = False; $retValue = FALSE;
if ((is_object($dateValue)) && ($dateValue instanceof self::$dateTimeObjectType)) { if ((is_object($dateValue)) && ($dateValue instanceof self::$dateTimeObjectType)) {
$retValue = self::FormattedPHPToExcel( $dateValue->format('Y'), $dateValue->format('m'), $dateValue->format('d'), $retValue = self::FormattedPHPToExcel( $dateValue->format('Y'), $dateValue->format('m'), $dateValue->format('d'),
$dateValue->format('H'), $dateValue->format('i'), $dateValue->format('s') $dateValue->format('H'), $dateValue->format('i'), $dateValue->format('s')
@ -204,12 +204,12 @@ class PHPExcel_Shared_Date
// Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel // Fudge factor for the erroneous fact that the year 1900 is treated as a Leap Year in MS Excel
// This affects every date following 28th February 1900 // This affects every date following 28th February 1900
// //
$excel1900isLeapYear = True; $excel1900isLeapYear = TRUE;
if (($year == 1900) && ($month <= 2)) { $excel1900isLeapYear = False; } if (($year == 1900) && ($month <= 2)) { $excel1900isLeapYear = FALSE; }
$myExcelBaseDate = 2415020; $myExcelBaseDate = 2415020;
} else { } else {
$myExcelBaseDate = 2416481; $myExcelBaseDate = 2416481;
$excel1900isLeapYear = False; $excel1900isLeapYear = FALSE;
} }
// Julian base date Adjustment // Julian base date Adjustment
@ -264,6 +264,10 @@ class PHPExcel_Shared_Date
public static function isDateTimeFormatCode($pFormatCode = '') { public static function isDateTimeFormatCode($pFormatCode = '') {
// Switch on formatcode // Switch on formatcode
switch ($pFormatCode) { switch ($pFormatCode) {
// General contains an epoch letter 'e', so we trap for it explicitly here
case PHPExcel_Style_NumberFormat::GENERAL:
return FALSE;
// Explicitly defined date formats
case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD: case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD:
case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2: case PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2:
case PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY: case PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY:
@ -286,32 +290,32 @@ class PHPExcel_Shared_Date
case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16: case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16:
case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17: case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17:
case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22: case PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22:
return true; return TRUE;
} }
// Typically number, currency or accounting (or occasionally fraction) formats // Typically number, currency or accounting (or occasionally fraction) formats
if ((substr($pFormatCode,0,1) == '_') || (substr($pFormatCode,0,2) == '0 ')) { if ((substr($pFormatCode,0,1) == '_') || (substr($pFormatCode,0,2) == '0 ')) {
return false; return FALSE;
} }
// Try checking for any of the date formatting characters that don't appear within square braces // Try checking for any of the date formatting characters that don't appear within square braces
if (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$pFormatCode)) { if (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$pFormatCode)) {
// We might also have a format mask containing quoted strings... // We might also have a format mask containing quoted strings...
// we don't want to test for any of our characters within the quoted blocks // we don't want to test for any of our characters within the quoted blocks
if (strpos($pFormatCode,'"') !== false) { if (strpos($pFormatCode,'"') !== FALSE) {
$i = false; $i = FALSE;
foreach(explode('"',$pFormatCode) as $subVal) { foreach(explode('"',$pFormatCode) as $subVal) {
// Only test in alternate array entries (the non-quoted blocks) // Only test in alternate array entries (the non-quoted blocks)
if (($i = !$i) && (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$subVal))) { if (($i = !$i) && (preg_match('/(^|\])[^\[]*['.self::$possibleDateFormatCharacters.']/i',$subVal))) {
return true; return TRUE;
} }
} }
return false; return FALSE;
} }
return true; return TRUE;
} }
// No date... // No date...
return false; return FALSE;
} // function isDateTimeFormatCode() } // function isDateTimeFormatCode()
@ -319,23 +323,23 @@ class PHPExcel_Shared_Date
* Convert a date/time string to Excel time * Convert a date/time string to Excel time
* *
* @param string $dateValue Examples: '2009-12-31', '2009-12-31 15:59', '2009-12-31 15:59:10' * @param string $dateValue Examples: '2009-12-31', '2009-12-31 15:59', '2009-12-31 15:59:10'
* @return float|false Excel date/time serial value * @return float|FALSE Excel date/time serial value
*/ */
public static function stringToExcel($dateValue = '') { public static function stringToExcel($dateValue = '') {
if (strlen($dateValue) < 2) if (strlen($dateValue) < 2)
return false; return FALSE;
if (!preg_match('/^(\d{1,4}[ \.\/\-][A-Z]{3,9}([ \.\/\-]\d{1,4})?|[A-Z]{3,9}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?|\d{1,4}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?)( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/iu', $dateValue)) if (!preg_match('/^(\d{1,4}[ \.\/\-][A-Z]{3,9}([ \.\/\-]\d{1,4})?|[A-Z]{3,9}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?|\d{1,4}[ \.\/\-]\d{1,4}([ \.\/\-]\d{1,4})?)( \d{1,2}:\d{1,2}(:\d{1,2})?)?$/iu', $dateValue))
return false; return FALSE;
$dateValueNew = PHPExcel_Calculation_DateTime::DATEVALUE($dateValue); $dateValueNew = PHPExcel_Calculation_DateTime::DATEVALUE($dateValue);
if ($dateValueNew === PHPExcel_Calculation_Functions::VALUE()) { if ($dateValueNew === PHPExcel_Calculation_Functions::VALUE()) {
return false; return FALSE;
} else { } else {
if (strpos($dateValue, ':') !== false) { if (strpos($dateValue, ':') !== FALSE) {
$timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($dateValue); $timeValue = PHPExcel_Calculation_DateTime::TIMEVALUE($dateValue);
if ($timeValue === PHPExcel_Calculation_Functions::VALUE()) { if ($timeValue === PHPExcel_Calculation_Functions::VALUE()) {
return false; return FALSE;
} }
$dateValueNew += $timeValue; $dateValueNew += $timeValue;
} }

View File

@ -89,6 +89,7 @@ Fixed in develop branch:
- Bugfix: (seltzlab) Fix to excel2007 Chart Writer when a $plotSeriesValues is empty - Bugfix: (seltzlab) Fix to excel2007 Chart Writer when a $plotSeriesValues is empty
- Bugfix: (MBaker) Work item 18370 - Error loading xlsx file with column breaks - Bugfix: (MBaker) Work item 18370 - Error loading xlsx file with column breaks
- Bugfix: (MBaker) OOCalc Reader now handles percentage and currency data types - Bugfix: (MBaker) OOCalc Reader now handles percentage and currency data types
- Bugfix: (MBaker) OOCalc Reader modified to process number-rows-repeated
2012-05-19 (v1.7.7): 2012-05-19 (v1.7.7):