Skip to content

Commit

Permalink
implemented and tested more methods to access a cell's value
Browse files Browse the repository at this point in the history
  • Loading branch information
jze committed Nov 30, 2024
1 parent 84069c0 commit 207d17a
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 51 deletions.
92 changes: 71 additions & 21 deletions src/main/java/de/zedlitz/opendocument/Cell.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
*/
package de.zedlitz.opendocument;

import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;


/**
Expand All @@ -23,10 +26,19 @@ public class Cell {
private final static QName ELEMENT_ANNOTATION = new QName(Document.NS_OFFICE, "annotation");
private final static String ATTRIBUTE_VALUE_TYPE = "value-type";
private final static String ATTRIBUTE_NUMBER_COLUMNS_REPEATED = "number-columns-repeated";
private static final String ATTRIBUTE_VALUE = "value";
private static final String ATTRIBUTE_BOOLEAN_VALUE = "boolean-value";
private static final String ATTRIBUTE_DATE_VALUE = "date-value";
private static final String ATTRIBUTE_TIME_VALUE = "time-value";
private static final String ATTRIBUTE_CURRENCY = "currency";

private final StringBuffer content = new StringBuffer();
private final int columnIndex;
private final Row row;
private String currency;
private String timeValue;
private String booleanValue;
private String value;
private String valueType;
private int numberColumnsRepeated;
private String dateValue;
Expand All @@ -42,6 +54,11 @@ public class Cell {
Document.NS_OFFICE, Cell.ATTRIBUTE_VALUE_TYPE),
Cell.TYPE_UNDEFINED);
this.dateValue = parser.getAttributeValue(Document.NS_OFFICE, Cell.ATTRIBUTE_DATE_VALUE);
this.value = parser.getAttributeValue(Document.NS_OFFICE, Cell.ATTRIBUTE_VALUE);
this.booleanValue = parser.getAttributeValue(Document.NS_OFFICE, Cell.ATTRIBUTE_BOOLEAN_VALUE);
this.timeValue = parser.getAttributeValue(Document.NS_OFFICE, Cell.ATTRIBUTE_TIME_VALUE);
this.currency = parser.getAttributeValue(Document.NS_OFFICE, Cell.ATTRIBUTE_CURRENCY);

this.numberColumnsRepeated = NumberUtils.toInt(parser.getAttributeValue(
Document.NS_TABLE, Cell.ATTRIBUTE_NUMBER_COLUMNS_REPEATED));

Expand Down Expand Up @@ -79,6 +96,22 @@ private static String getColumnName(int columnIndex) {
return columnName.toString();
}

public String getCurrency() {
return currency;
}

public String getTimeValue() {
return timeValue;
}

public String getBooleanValue() {
return booleanValue;
}

public String getDateValue() {
return dateValue;
}

private void skipNote(final XMLStreamReader parser)
throws XMLStreamException {
int eventType = parser.getEventType();
Expand All @@ -97,7 +130,11 @@ public String getValueType() {
}

/**
* @see de.zedlitz.opendocument.Cell#getContent()
* Returns the content of the cell formatted for the locale of the file. For example in a German ods file the
* boolean value <code>true</code> will be returned as <code>WAHR</code>. In a French ods file it will be
* <code>VRAI</code>. And in an English ods file it will be <code>TRUE</code>.
* <p/>
* If you are looking for a language independent value you can use the getValue method.
*/
public String getContent() {
return this.content.toString();
Expand All @@ -112,18 +149,15 @@ public int getNumberColumnsRepeated() {
*/
@Override
public String toString() {
return getContent();
return String.format("[%s \"%s\"]", getValueType(), getContent());
}

public CellType getType() {
if ("string".equals(valueType)) {
return CellType.STRING;
public Boolean asBoolean() {
if ("boolean".equals(valueType) && StringUtils.isNotEmpty(booleanValue)) {
return Boolean.valueOf(booleanValue);
}
if ("float".equals(valueType) || "currency".equals(valueType) || "date".equals(valueType)
|| "percentage".equals(valueType) || "time".equals(valueType)) {
return CellType.NUMBER;
}
return CellType.EMPTY;

throw new OdsReaderException("Wrong cell type " + valueType + " for boolean value");
}

public LocalDate asDate() {
Expand All @@ -134,20 +168,27 @@ public LocalDate asDate() {
throw new OdsReaderException("Wrong cell type " + valueType + " for date value");
}

public String getDataFormatString() {
throw new NotImplementedException();
}
public LocalDateTime asDateTime() {
if ("date".equals(valueType) && StringUtils.isNotEmpty(dateValue)) {
if (dateValue.contains("T")) {
// date and time
return LocalDateTime.parse(dateValue, DateTimeFormatter.ISO_DATE_TIME);
} else {
// only date
return LocalDateTime.parse(dateValue+"T00:00:00", DateTimeFormatter.ISO_DATE_TIME);
}
}

public Object getValue() {
throw new NotImplementedException();
throw new OdsReaderException("Wrong cell type " + valueType + " for date value");
}

public String getText() {
return getContent();
}
public LocalTime asTime() {
if ("time".equals(valueType) && StringUtils.isNotEmpty(timeValue)) {
Duration duration = Duration.parse(timeValue);
return LocalTime.ofSecondOfDay(duration.getSeconds());
}

public String getRawValue() {
return getContent();
throw new OdsReaderException("Wrong cell type " + valueType + " for time value");
}

public int getColumnIndex() {
Expand All @@ -157,4 +198,13 @@ public int getColumnIndex() {
public String getAddress() {
return getColumnName(columnIndex) + row.getRowNum();
}

/**
* Returns the language independent value of a cell.
*/
public String getValue() {
return value;
}


}
119 changes: 95 additions & 24 deletions src/test/java/de/zedlitz/opendocument/CellTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.*;

public class CellTest extends AbstractBaseTest {
private static final String CONTENT_EMPTY_CELL =
Expand All @@ -23,7 +25,7 @@ public void empty() throws Exception {
final Cell cell = new Cell(advanceToStartTag(createParser(CONTENT_EMPTY_CELL)), new DummyRow(), 0);

assertEquals(StringUtils.EMPTY, cell.getContent());
assertEquals(StringUtils.EMPTY, cell.toString());
assertEquals("[undefined \"\"]", cell.toString());
}

@Test
Expand All @@ -38,17 +40,21 @@ private Row getRowFromDemoFile() throws XMLStreamException, IOException {
return table.nextRow();
}

@Test
public void testGetType() throws XMLStreamException, IOException {
Row row = getRowFromDemoFile();
assertEquals(CellType.STRING, row.nextCell().getType());
assertEquals(CellType.NUMBER, row.nextCell().getType());
assertEquals(CellType.NUMBER, row.nextCell().getType());
assertEquals(CellType.NUMBER, row.nextCell().getType());
assertEquals(CellType.NUMBER, row.nextCell().getType());
assertEquals(CellType.NUMBER, row.nextCell().getType());
assertEquals(CellType.NUMBER, row.nextCell().getType());
assertEquals(CellType.NUMBER, row.nextCell().getType());
/**
* In this demo file all the interesting cells are beneath each other in the first column.
*/
private List<Cell> getCellsFromDemoFile(String resourceName) throws XMLStreamException, IOException {
List<Cell> cells = new ArrayList<>();

final Document doc = new Document(getClass().getResourceAsStream(resourceName));
Table table = doc.nextTable();
Row row = table.nextRow();

while (row != null) {
cells.add(row.nextCell());
row = table.nextRow();
}
return cells;
}

@Test
Expand Down Expand Up @@ -88,21 +94,86 @@ public void testGetAddress() throws Exception {
@Test
public void testGetText() throws Exception {
Row row = getRowFromDemoFile();
assertEquals("abc", row.nextCell().getText());
assertEquals("7392", row.nextCell().getText());
assertEquals("5.039", row.nextCell().getText());
assertEquals("2024-07-01", row.nextCell().getText());
assertEquals("5,63 %", row.nextCell().getText());
assertEquals("78,34 €", row.nextCell().getText());
assertEquals("08:35", row.nextCell().getText());
assertEquals("54,143662", row.nextCell().getText());
assertEquals("abc", row.nextCell().getContent());
assertEquals("7392", row.nextCell().getContent());
assertEquals("5.039", row.nextCell().getContent());
assertEquals("2024-07-01", row.nextCell().getContent());
assertEquals("5,63 %", row.nextCell().getContent());
assertEquals("78,34 €", row.nextCell().getContent());
assertEquals("08:35", row.nextCell().getContent());
assertEquals("54,143662", row.nextCell().getContent());
}

@Test
public void testAsDate() throws Exception {
Row row = getRowFromDemoFile();
assertEquals(LocalDate.of(2024,7,1), row.getAt(3).asDate());
List<Cell> cells = getCellsFromDemoFile("/formats_german.ods");
assertThrows(OdsReaderException.class, () -> cells.get(0).asDate());
assertEquals(LocalDate.of(1999, 12, 31), cells.get(11).asDate());
}

@Test
public void testAsDateTime() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_german.ods");
assertThrows(OdsReaderException.class, () -> cells.get(0).asDateTime());
// 1999-12-31
assertEquals(LocalDateTime.of(1999, 12, 31, 0, 0, 0), cells.get(11).asDateTime());
// 1999-12-31T07:35:02
assertEquals(LocalDateTime.of(1999, 12, 31, 7, 35, 2), cells.get(22).asDateTime());
// 1899-12-30T13:37:46
assertEquals(LocalDateTime.of(1899, 12, 30, 13, 37, 46), cells.get(28).asDateTime());
}

@Test
public void testGetDateValue() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_german.ods");
assertNull(cells.get(0).getDateValue());
assertEquals("1999-12-31", cells.get(11).getDateValue());
assertEquals("1999-12-31T07:35:02", cells.get(22).getDateValue());
assertEquals("1899-12-30T13:37:46", cells.get(28).getDateValue());
}
@Test
public void testAsBoolean() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_french.ods");
assertThrows(OdsReaderException.class, () -> cells.get(0).asBoolean());
assertTrue(cells.get(33).asBoolean());
assertFalse(cells.get(34).asBoolean());
}

@Test
public void testGetBoolean() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_french.ods");
assertNull(cells.get(0).getBooleanValue());
assertEquals("true", cells.get(33).getBooleanValue());
assertEquals("false", cells.get(34).getBooleanValue());
}

@Test
public void testGetCurrency() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_german.ods");
assertNull(cells.get(0).getCurrency());
assertEquals("EUR", cells.get(8).getCurrency());
assertEquals("DEM", cells.get(9).getCurrency());
}

@Test
public void testAsTime() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_german.ods");
assertThrows(OdsReaderException.class, () -> cells.get(0).asTime());
assertEquals(LocalTime.of(13, 37, 46), cells.get(26).asTime());
}

@Test
public void testGetTimeValue() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_german.ods");
assertNull(cells.get(0).getTimeValue());
assertEquals("PT13H37M46S", cells.get(26).getTimeValue());
}

@Test
public void testGetValue() throws Exception {
List<Cell> cells = getCellsFromDemoFile("/formats_french.ods");
assertEquals("50000", cells.get(0).getValue());
assertEquals("0.1295", cells.get(7).getValue());
assertEquals("120.5", cells.get(8).getValue());
}
}
Loading

0 comments on commit 207d17a

Please sign in to comment.