Skip to content

Commit

Permalink
Add option to evaluate formulas in XLSX files
Browse files Browse the repository at this point in the history
Nonda95 authored and koral-- committed Dec 6, 2019
1 parent 4a300d9 commit 6c08d26
Showing 10 changed files with 78 additions and 10 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ Generation has to be invoked as additional gradle task. Java 1.8 is required.
* comments
* formatted strings - `formatted` XML attribute
* default locale specification - `tools:locale`
* evaluate cell formulas

## Applying plugin
### Gradle 2.1+
@@ -153,6 +154,7 @@ possible values:
* `sheetName` - default=`<name of the first sheet>`, name of the sheet to be processed, only one can be specified,
ignored if `useAllSheets` is set to true
* `useAllSheets` - default=`false`, if set to true all sheets are processed and `sheetName` is ignored
* `evaluateFormulas` - default=`false`, if set to true evaluates formulas in cells

#### Advanced options:
* `ignorableColumns` - default=`[]`, columns from that list will be ignored during parsing. List should
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ class ConfigExtension {
boolean convertTripleDotsToHorizontalEllipsis = true
boolean escapeSlashes = true
boolean useAllSheets = false
boolean evaluateFormulas = false
TagEscapingStrategy tagEscapingStrategy = TagEscapingStrategy.IF_TAGS_ABSENT
Normalizer.Form normalizationForm = Normalizer.Form.NFC
String defaultColumnName = 'default'
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ class ParserEngine {
mParser = config.csvStrategy ? new CSVInnerParser(reader, config.csvStrategy) : new CSVInnerParser(reader)
} else {
def isXLS = sourceType == SourceType.XLS
mParser = new XLSXParser((InputStream) mCloseableInput, isXLS, config.sheetName, config.useAllSheets)
mParser = new XLSXParser((InputStream) mCloseableInput, isXLS, config.sheetName, config.useAllSheets, config.evaluateFormulas)
}
}

Original file line number Diff line number Diff line change
@@ -1,42 +1,42 @@
package pl.droidsonroids.gradle.localization

import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.ss.usermodel.Sheet
import org.apache.poi.ss.usermodel.Workbook
import org.apache.poi.ss.usermodel.*
import org.apache.poi.xssf.usermodel.XSSFWorkbook

class XLSXParser implements Parser {

private Map<String, String[][]> mAllSheets

XLSXParser(InputStream inputStream, boolean isXls, String sheetName, boolean useAllSheets) {
XLSXParser(InputStream inputStream, boolean isXls, String sheetName, boolean useAllSheets, boolean evaluateFormulas) {
Workbook workbook = isXls ? new HSSFWorkbook(inputStream) : new XSSFWorkbook(inputStream)
workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK)

FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator()
if (useAllSheets) {
mAllSheets = new HashMap<>(workbook.numberOfSheets)
for (Sheet sheet : workbook.sheetIterator()) {
mAllSheets.put(sheet.getSheetName(), getAllValues(sheet))
mAllSheets.put(sheet.getSheetName(), getAllValues(sheet, evaluator, evaluateFormulas))
}
} else {
mAllSheets = new HashMap<>(1)
Sheet sheet = sheetName ? workbook.getSheet(sheetName) : workbook.getSheetAt(0)
if (sheet == null)
throw new IllegalArgumentException("Sheet $sheetName does not exist")
mAllSheets.put(null, getAllValues(sheet))
mAllSheets.put(null, getAllValues(sheet, evaluator, evaluateFormulas))
}
}

static String[][] getAllValues(Sheet sheet) {
static String[][] getAllValues(Sheet sheet, FormulaEvaluator evaluator, boolean evaluateFormulas) {
String[][] allCells = new String[sheet.lastRowNum + 1][]
for (int i = 0; i <= sheet.lastRowNum; i++) {
Row row = sheet.getRow(i)
if (row == null)
continue
allCells[i] = new String[row.lastCellNum]
for (int j = 0; j < row.lastCellNum; j++) {
allCells[i][j] = row.getCell(j).toString() ?: ""
Cell cell = row.getCell(j)
if (evaluateFormulas) evaluator.evaluateInCell(cell)
allCells[i][j] = cell.toString() ?: ""
}
}
return allCells
Original file line number Diff line number Diff line change
@@ -82,4 +82,37 @@ class ParseXLSXTest extends LocalizationPluginTestBase {
config.xlsFileURI = 'https://docs.google.com/a/droidsonroids.pl/spreadsheets/d/1sfE3Zk_7syHpq3HPKYQ9gRidm1W7c1IjIfdH1R8z9m4/export?format=xlsx'
parseTestFile(config)
}

@Test
void testXlsxFileWithFormulas() {
def name = 'valid_formulas.xlsx'

ConfigExtension config = new ConfigExtension()
config.xlsFileURI = getClass().getResource(name).toString()
config.allowEmptyTranslations = true
config.skipInvalidName = true
config.skipDuplicatedName = true
config.evaluateFormulas = true
config.defaultColumnName = 'EN'
config.nameColumnName = 'Android'
config.ignorableColumns.add('WinPhone')
config.ignorableColumns.add('iOS')
config.ignorableColumns.add('END')
config.defaultLocaleQualifier = 'en'
config.useAllSheets = true

def resDir = parseTestFile(config)

resDir.traverse(type: FileType.FILES) {
def filePath = it.path.replace(resDir.path, '')
def expectedFileURL = getClass().getResource("parsed_valid_formulas_xlsx/$filePath")
def diff = DiffBuilder.compare(Input.fromFile(it))
.withTest(Input.fromURL(expectedFileURL))
.ignoreWhitespace()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndAllAttributes))
.checkForSimilar()
.build()
assertThat(diff.hasDifferences()).as('file: %s is different than expected %s', filePath, diff.toString()).isFalse()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources/>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="file">Plik</string><!-- file label -->
<string name="empty"></string>
<plurals name="cow">
<item quantity="other">krowy</item><!-- comment -->
<item quantity="one">krowa</item>
</plurals>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:locale="en">
<string name="copyright" translatable="false">koral--</string>
</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:locale="en">
<string name="app" translatable="false">Application</string>
<string name="file">File</string><!-- file label -->
<string name="percent" translatable="false" formatted="false">%d %s</string>
<string name="empty"></string>
<string name="formula" translatable="false">monday, tuesday, wednesday</string>
<plurals name="cow">
<item quantity="other">cows</item><!-- comment -->
<item quantity="one">cow</item>
</plurals>
<string-array name="days" translatable="false">
<item>monday</item>
<item>tuesday</item>
<item>wednesday</item>
</string-array>
</resources>
Binary file not shown.

0 comments on commit 6c08d26

Please sign in to comment.