All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.pjfanning.xlsx.impl.StreamingCell Maven / Gradle / Ivy

The newest version!
package com.github.pjfanning.xlsx.impl;

import com.github.pjfanning.xlsx.XmlUtils;
import com.github.pjfanning.xlsx.exceptions.NotSupportedException;
import org.apache.poi.ooxml.POIXMLException;
import org.apache.poi.ss.formula.FormulaParseException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;

import static com.github.pjfanning.xlsx.impl.NumberUtil.parseDouble;

public class StreamingCell implements Cell {

  private static final Supplier NULL_SUPPLIER = () -> null;

  private final Sheet sheet;
  private final int columnIndex;
  private int rowIndex;
  private Row row;
  private final boolean use1904Dates;

  private Supplier contentsSupplier = NULL_SUPPLIER;
  private String rawContents;
  private String formula;
  private String numericFormat;
  private Short numericFormatIndex;
  private String type;
  private CellStyle cellStyle;
  private boolean formulaType;
  private boolean sharedFormula;
  private String formulaSI;

  public StreamingCell(Sheet sheet, int columnIndex, int rowIndex, boolean use1904Dates) {
    this.sheet = sheet;
    this.columnIndex = columnIndex;
    this.rowIndex = rowIndex;
    this.use1904Dates = use1904Dates;
  }

  public StreamingCell(Sheet sheet, int columnIndex, Row row, boolean use1904Dates) {
    this.sheet = sheet;
    this.columnIndex = columnIndex;
    this.row = row;
    this.use1904Dates = use1904Dates;
  }

  void setContentSupplier(Supplier contentsSupplier) {
    this.contentsSupplier = contentsSupplier;
  }

  void setRawContents(String rawContents) {
    this.rawContents = rawContents;
  }

  public String getNumericFormat() {
    return numericFormat;
  }

  void setNumericFormat(String numericFormat) {
    this.numericFormat = numericFormat;
  }

  Short getNumericFormatIndex() {
    return numericFormatIndex;
  }

  void setNumericFormatIndex(Short numericFormatIndex) {
    this.numericFormatIndex = numericFormatIndex;
  }

  void setFormula(String formula) {
    this.formula = formula;
  }

  String getType() {
    return type;
  }

  void setType(String type) {
    this.type = type;
  }

  boolean isFormulaType() {
    return formulaType;
  }

  void setFormulaType(boolean formulaType) {
    this.formulaType = formulaType;
  }

  void setSharedFormula(boolean sharedFormula) {
    this.sharedFormula = sharedFormula;
  }

  boolean isSharedFormula() {
    return sharedFormula;
  }

  void setFormulaSI(String formulaSI) {
    this.formulaSI = formulaSI;
  }

  String getFormulaSI() {
    return formulaSI;
  }

  @Override
  public void setCellStyle(CellStyle cellStyle) {
    this.cellStyle = cellStyle;
  }

  /* Supported */

  /**
   * Returns column index of this cell
   *
   * @return zero-based column index of a column in a sheet.
   */
  @Override
  public int getColumnIndex() {
    return columnIndex;
  }

  /**
   * Returns row index of a row in the sheet that contains this cell
   *
   * @return zero-based row index of a row in the sheet that contains this cell
   */
  @Override
  public int getRowIndex() {
    return (row == null) ? rowIndex : row.getRowNum();
  }

  /**
   * Row is not guaranteed to be set. Will return null when row is not set.
   */
  @Override
  public Row getRow() {
    return row;
  }

  @Override
  public Sheet getSheet() {
    return sheet;
  }

  /**
   * Return the cell type.
   *
   * @return the cell type
   * @throws POIXMLException if the value is not parseable
   */
  @Override
  public CellType getCellType() throws POIXMLException {
    if (formulaType) {
      return CellType.FORMULA;
    } else if (contentsSupplier.getContent() == null || type == null) {
      return CellType.BLANK;
    }
    return getCellTypeFromShortHandType(type);
  }

  /**
   * Get the value of the cell as a string.
   * For blank cells, we return an empty string.
   *
   * @return the value of the cell as a string
   * @throws POIXMLException if the value is not parseable
   */
  @Override
  public String getStringCellValue() throws POIXMLException {
    Object c = contentsSupplier.getContent();

    return c == null ? "" : c.toString();
  }

  /**
   * Get the value of the cell as a number. For strings, we throw an exception. For
   * blank cells, we return a 0.
   *
   * @return the value of the cell as a number
   * @throws NumberFormatException if the cell value isn't a parseable double.
   */
  @Override
  public double getNumericCellValue() {
    if ("d".equals(type)) {
      try {
        LocalDateTime dt = DateTimeUtil.parseDateTime(rawContents);
        return DateUtil.getExcelDate(dt, use1904Dates);
      } catch (Exception e) {
        try {
          return DateTimeUtil.convertTime(rawContents);
        } catch (Exception e2) {
          throw new IllegalStateException("cannot parse strict format date/time " + rawContents);
        }
      }
    }
    return rawContents == null ? 0.0 : parseDouble(rawContents);
  }

  /**
   * Get the value of the cell as a date. For strings, we throw an exception. For
   * blank cells, we return a null.
   *
   * @return the value of the cell as a date
   * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is CELL_TYPE_STRING
   * @throws NumberFormatException if the cell value isn't a parseable double.
   */
  @Override
  public Date getDateCellValue() {
    if(getCellType() == CellType.STRING) {
      throw new IllegalStateException("Cell type cannot be CELL_TYPE_STRING");
    }
    return rawContents == null ? null : DateUtil.getJavaDate(getNumericCellValue(), use1904Dates);
  }

  /**
   * Get the value of the cell as a boolean. For strings, we throw an exception. For
   * blank cells, we return a false.
   *
   * @return the value of the cell as a date
   */
  @Override
  public boolean getBooleanCellValue() {
    CellType cellType = getCellType();

    if (cellType == CellType.FORMULA) {
      cellType = getCachedFormulaResultType();
    }
    switch(cellType) {
      case BLANK:
        return false;
      case BOOLEAN:
        return rawContents != null && XmlUtils.evaluateBoolean(rawContents);
      default:
        throw typeMismatch(CellType.BOOLEAN, cellType, isFormulaType());
    }
  }

  private static IllegalStateException typeMismatch(CellType expectedType, CellType actualType, boolean isFormulaCell) {
    String msg = "Cannot get a "
            + getCellTypeName(expectedType) + " value from a "
            + getCellTypeName(actualType) + " " + (isFormulaCell ? "formula " : "") + "cell";
    return new IllegalStateException(msg);
  }

  /**
   * Used to help format error messages
   */
  private static String getCellTypeName(CellType cellType) {
    switch (cellType) {
      case BLANK:   return "blank";
      case STRING:  return "text";
      case BOOLEAN: return "boolean";
      case ERROR:   return "error";
      case NUMERIC: return "numeric";
      case FORMULA: return "formula";
      default:
        return "#unknown cell type (" + cellType + ")#";
    }
  }

  /**
   * @return the style of the cell
   */
  @Override
  public CellStyle getCellStyle() {
    return this.cellStyle;
  }

  /**
   * Return a formula for the cell, for example, SUM(C4:E4)
   *
   * @return a formula for the cell
   * @throws IllegalStateException if the cell type returned by {@link #getCellType()} is not CELL_TYPE_FORMULA or
   *                               if the cell has a shared formula that can't be evaluated
   */
  @Override
  public String getCellFormula() {
    if (!formulaType)
      throw new IllegalStateException("This cell does not have a formula");
    if ((formula == null || formula.isEmpty()) && sharedFormula)
      throw new IllegalStateException("This cell has a shared formula and it seems setReadSharedFormulas has been set to false or the formula can't be evaluated");
    return formula;
  }

  /**
   * Get the value of the cell as a XSSFRichTextString
   * 

* For numeric cells, we throw an exception. For blank cells, we return an empty string. * For formula cells, we return the pre-calculated value if a string, otherwise an exception *

* @return the value of the cell as a XSSFRichTextString * @throws NotSupportedException if the cell type is unsupported * @throws POIXMLException if the value is not parseable */ @Override public XSSFRichTextString getRichStringCellValue() throws POIXMLException { CellType cellType = getCellType(); if (cellType == CellType.FORMULA) { cellType = getCachedFormulaResultType(); } XSSFRichTextString rt; switch (cellType) { case BLANK: rt = new XSSFRichTextString(""); break; case STRING: Object content = contentsSupplier.getContent(); if (content instanceof XSSFRichTextString) { rt = (XSSFRichTextString)content; } else if (content != null) { rt = new XSSFRichTextString(content.toString()); } else { rt = new XSSFRichTextString(""); } break; default: throw new NotSupportedException("getRichStringCellValue does not support cell type " + cellType); } return rt; } /** * Only valid for formula cells * @return one of ({@link CellType#NUMERIC}, {@link CellType#STRING}, * {@link CellType#BOOLEAN}, {@link CellType#ERROR}) depending * on the cached value of the formula * @throws IllegalStateException if cell is not formula type * @throws NotSupportedException if cell formula type is unknown * @throws POIXMLException if the value is not parseable */ @Override public CellType getCachedFormulaResultType() throws POIXMLException { if (formulaType) { if (contentsSupplier.getContent() == null || type == null) { return CellType.BLANK; } return getCellTypeFromShortHandType(type); } else { throw new IllegalStateException("Only formula cells have cached results"); } } @Override public LocalDateTime getLocalDateTimeCellValue() { if(getCellType() == CellType.STRING) { throw new IllegalStateException("Cell type cannot be CELL_TYPE_STRING"); } return rawContents == null ? null : DateUtil.getLocalDateTime(getNumericCellValue(), use1904Dates); } @Override public byte getErrorCellValue() { CellType cellType = getCellType(); if(cellType != CellType.ERROR) { throw typeMismatch(CellType.ERROR, cellType, false); } String code = rawContents; if (code == null) { return 0; } try { return FormulaError.forString(code).getCode(); } catch (final IllegalArgumentException e) { throw new IllegalStateException("Unexpected error code", e); } } @Override public CellAddress getAddress() { return new CellAddress(this); } /** * Returns cell comment associated with this cell * * @return the cell comment associated with this cell or {@code null} * @throws IllegalStateException if {@link com.github.pjfanning.xlsx.StreamingReader.Builder#setReadComments(boolean)} is not set to true */ @Override public Comment getCellComment() { return (sheet == null) ? null : sheet.getCellComment(getAddress()); } /** * Returns hyperlink associated with this cell. This is not recommended as this data is stored at the end * of the sheet. Use the hyperlink methods on sheet instance instead or keep this cell instance in memory * until after all the rows have been read. * * @return the hyperlink associated with this cell or {@code null} * @throws IllegalStateException if {@link com.github.pjfanning.xlsx.StreamingReader.Builder#setReadHyperlinks(boolean)} is not set to true */ @Override public Hyperlink getHyperlink() { return (sheet == null) ? null : sheet.getHyperlink(getAddress()); } /* Not supported */ /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellType(CellType cellType) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setBlank() { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(double value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(Date value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(Calendar value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(LocalDate value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(LocalDateTime value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(RichTextString value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(String value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellFormula(String formula) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void removeFormula() { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellValue(boolean value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellErrorValue(byte value) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setAsActiveCell() { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setCellComment(Comment comment) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void removeCellComment() { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void setHyperlink(Hyperlink link) { throw new NotSupportedException("update operations are not supported"); } /** * Update operations are not supported * * @throws NotSupportedException not supported */ @Override public void removeHyperlink() { throw new NotSupportedException("update operations are not supported"); } /** * Not supported * * @throws NotSupportedException not supported */ @Override public CellRangeAddress getArrayFormulaRange() { throw new NotSupportedException(); } /** * Not supported * * @throws NotSupportedException not supported */ @Override public boolean isPartOfArrayFormulaGroup() { throw new NotSupportedException(); } private static CellType getCellTypeFromShortHandType(final String cellType) { switch (cellType) { case "n": case "d": return CellType.NUMERIC; case "s": case "inlineStr": case "str": return CellType.STRING; case "b": return CellType.BOOLEAN; case "e": return CellType.ERROR; } throw new UnsupportedOperationException("Unsupported cell cell type '" + cellType + "'"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy