Search code examples
javaexcelinternationalizationlocalexlsx

How to read 2 columns from excel file (xlsx) and write it to resource properties as key=value pair


I am trying to generate messages_[en/da/bg].properties file from the given set for excel (xlsx) files. Each excel sheet is provided with two columns as key-value pair. I have to read each file and write it to generate messages_en.properties file for i18n.

If I have excel sheets with filenames like locales_ENG.xlsx, locales_DAN.xlsx & locales_BGR.xlsx then it should generate files as: messages_en.properties messages_da.properties messages_bg.properties


Solution

  • I tried solving the problem by adding the Apache POI as a dependency in order to read excel file.

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.17</version>
    </dependency>
    

    and for writing the key-value pair I have used java Properties class.

    public class App {
    
    LinkedHashMap<String, String> map = new LinkedHashMap<>();
    
    public static void main(String[] args) throws IOException {
    
        final App app = new App();
    
        for (final Locale locale : Locale.values()) {
    
            app.readExcelFile("locales_" + locale + ".xlsx");
    
            app.writeToPropertiesFile("messages_" + locale.name().substring(0, 2).toLowerCase() + ".properties");
    
        }
    
    }
    
    public void writeToPropertiesFile(String propertiesPath) throws IOException {
    
        final LinkedProperties props = new LinkedProperties();
    
        map.entrySet().forEach(entry -> props.setProperty(entry.getKey(), entry.getValue()));
    
        props.store(new FileOutputStream(new File(propertiesPath)), null);
    
    }
    
    public void readExcelFile(String fileName) throws IOException {
    
        Workbook workbook = null;
    
        XSSFCell cell1 = null;
    
        XSSFCell cell2 = null;
    
        try {
    
            workbook = WorkbookFactory.create(new File(fileName));
    
            final XSSFSheet sheet = (XSSFSheet) workbook.getSheetAt(0);
    
            final Iterator<Row> rowIterator = sheet.rowIterator();
    
            // skip first row which is header
            rowIterator.next();
    
            while (rowIterator.hasNext()) {
    
                final XSSFRow row = (XSSFRow) rowIterator.next();
    
                final Iterator<Cell> cellIterator = row.cellIterator();
    
                while (cellIterator.hasNext()) {
    
                    cell1 = (XSSFCell) cellIterator.next();
    
                    final String key = cell1.getRichStringCellValue().toString();
    
                    if (key == "")
                        break;
    
                    cell2 = (XSSFCell) cellIterator.next();
    
                    final String value = cell2.getRichStringCellValue().toString();
    
                    map.put(key, value);
    
                }
            }
        }
    
        catch (final Exception e) {
    
        } finally {
    
            if (workbook != null)
    
                workbook.close();
        }
    }
    

    }

    In order to maintain the order of the key-value in the properties file, I have created custom properties class i.e. LinkedProperties which extends Properties class.

    public class LinkedProperties extends Properties {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    
    private final HashSet<Object> keys = new LinkedHashSet<>();
    
    public LinkedProperties() {
        // Nothing is done here
    }
    
    public Iterable<Object> orderedKeys() {
        return Collections.list(keys());
    }
    
    @Override
    public Enumeration<Object> keys() {
        return Collections.<Object>enumeration(keys);
    }
    
    @Override
    public Object put(Object key, Object value) {
        keys.add(key);
        return super.put(key, value);
    }
    
    @Override
    public synchronized boolean equals(Object o) {
        return super.equals(o);
    }
    
    @Override
    public synchronized int hashCode() {
        return super.hashCode();
    }
    

    }