1. 程式人生 > >使用POI和dom4j來解析Excel生成Xml

使用POI和dom4j來解析Excel生成Xml

工作中有時候我們需要使用Apache的POI來讀寫Excel檔案,而dom4j則用來解析或者生成Xml檔案,由於涉及到IO流,所以又使用了commons-io提供的IOUtils來關閉流。

需要的Jar包

一個應用POI和dom4j的簡單例子

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

public class MyPOI {

    private boolean elemStarted = false;
    private boolean attrStarted = false;
    Element tabNode;
    Element elemsNode;
    Element elemNode;
    Element subNode;
    private final List<String> list = new ArrayList<String>();

    public void parseExcel(final String src, final String target) throws Exception {

        XSSFWorkbook workbook = null;
        XSSFSheet sheet = null;
        XMLWriter writer = null;
        InputStream fin = null;
        OutputStream fos = null;
        final File srcFile = new File(src);
        final String fileName = srcFile.getName();
        final Document doc = DocumentHelper.createDocument();
        // create the root element
        final Element root = doc.addElement(fileName.substring(0, fileName.indexOf('.')));
        root.addAttribute("position", fileName);
        try {
            fin = new FileInputStream(srcFile);
            fos = new FileOutputStream(target);
            workbook = new XSSFWorkbook(fin);
            final int sheetNum = workbook.getNumberOfSheets();
            for (int i = 0; i < sheetNum; i++) {
                sheet = workbook.getSheetAt(i);
                if (sheet == null) {
                    continue;
                }
                // create the sheet element
                final Element sheetNode = root.addElement("sheet");
                sheetNode.addAttribute("id", sheet.getSheetName());
                sheetNode.addAttribute("position", fileName + "," + sheet.getSheetName());
                final int rowNum = sheet.getLastRowNum();
                for (int j = 0; j <= rowNum; j++) {
                    final XSSFRow row = sheet.getRow(j);
                    if (row == null) {
                        continue;
                    }
                    final XSSFCell firstCell = row.getCell(0);
                    final String firstCellValue = getCellValue(firstCell);
                    if (firstCell == null || "".equals(firstCellValue)) {
                        continue;
                    }
                    if (firstCellValue.startsWith("#end_attr")) {
                        attrStarted = false;
                        continue;
                    }
                    if (firstCellValue.startsWith("#end_elem")) {
                        elemStarted = false;
                        continue;
                    }
                    if (firstCellValue.startsWith("##")) {
                        // create the tab element
                        tabNode = sheetNode.addElement(firstCellValue.substring(2));
                        tabNode.addAttribute("position", fileName + "," + sheet.getSheetName() + "," + (j+1));
                    } else if (firstCellValue.startsWith("#begin")) {
                        j++;
                        final XSSFRow nextRow = sheet.getRow(j);
                        final int nextRowCellNum = nextRow.getLastCellNum();
                        if (firstCellValue.startsWith("#begin_attr")) {
                            attrStarted = true;
                        } else if (firstCellValue.startsWith("#begin_elem")) {
                            elemStarted = true;
                            // create the elements element
                            elemsNode = tabNode.addElement("elements");
                            if (firstCellValue.indexOf(":") == -1) {
                                elemsNode.addAttribute("id", "default");
                            } else {
                                elemsNode.addAttribute("id", firstCellValue.split(":")[1]);
                            }
                        }
                        if (!list.isEmpty()) {
                            list.clear();
                        }
                        for (int k = 0; k < nextRowCellNum; k++) {
                            final XSSFCell nextRowCell = nextRow.getCell(k);
                            String cellValue = getCellValue(nextRowCell);
                            if (nextRowCell != null && !"".equals(cellValue)) {
                                if (cellValue.endsWith("*")) {
                                    cellValue = cellValue.substring(0, cellValue.length() - 1);
                                }
                                list.add(cellValue);
                            }
                        }
                    } else {
                        processRow(row);
                    }
                }
            }
            writer = new XMLWriter(fos, OutputFormat.createPrettyPrint());
            writer.write(doc);
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (final IOException e) {
                    e.printStackTrace();
                }
            }
            IOUtils.closeQuietly(fin);
            IOUtils.closeQuietly(fos);
        }
    }

    private String getCellValue(final Cell cell) {
        String value = "";
        if (cell == null) {
            return value;
        }
        if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
            cell.setCellType(Cell.CELL_TYPE_STRING);
        }
        switch (cell.getCellType()) {
        case Cell.CELL_TYPE_STRING:
            if (cell.getStringCellValue().startsWith("( *")) {
                value = "";
            } else {
                value = cell.getStringCellValue();
            }
            break;
        case Cell.CELL_TYPE_NUMERIC:
            value = String.valueOf(cell.getNumericCellValue());
            break;
        case Cell.CELL_TYPE_BOOLEAN:
            value = String.valueOf(cell.getBooleanCellValue());
            break;
        case Cell.CELL_TYPE_FORMULA:
            value = String.valueOf(cell.getCellFormula());
            break;
        case Cell.CELL_TYPE_BLANK:
            value = "";
            break;
        default:
            break;
        }

        return value;
    }

    private void processRow(final XSSFRow row) {
        if (attrStarted) {
            for (int i = 0; i < list.size(); i++) {
                final XSSFCell cell = row.getCell(i);
                tabNode.addAttribute(list.get(i), getCellValue(cell));
            }
        }
        if (elemStarted) {
            elemNode = elemsNode.addElement("element");
            final String tabPosition = tabNode.attributeValue("position");
            final String positionPrefix = tabPosition.substring(0, tabPosition.lastIndexOf(","));
            elemNode.addAttribute("position", positionPrefix + "," + (row.getRowNum() + 1));
            for (int i = 0; i < list.size(); i++) {
                final XSSFCell cell = row.getCell(i);
                subNode = elemNode.addElement(list.get(i));
                if (!"".equals(getCellValue(cell))) {
                    subNode.setText(getCellValue(cell));
                }
            }
        }
    }

}

在上邊的類中,要注意流的關閉,不要直接在try塊裡邊關閉,應該在finally裡邊使用IOUtils的closeQuietly方法來關閉,這樣就可以不用自己去判斷流是否為null,也不用自己再去try-catch流的close方法。接著是一個測試類。

public class POITest {

    public static void main(final String[] args) {
        final ResourceBundle rb = ResourceBundle.getBundle("xml-generator");
        final String src = rb.getString("gen.excel.path");
        final String target = rb.getString("gen.target.path");
        try {
            new LewisPOI().parseExcel(src, target);
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

}

在POITest類,為了避免路徑字串的硬編碼,我將路徑存放到了一個名為xml-generator的properties檔案中,該配置檔案存放在專案的src目錄下。該配置檔案存放的是要讀取的excel的路徑,以及要生成的xml檔案的路徑,這裡需要注意兩個檔案的目錄是否正確,否則會無法正確的讀取excel或者生成xml(可以自己先在程式碼中判斷目錄是否存在,若不存在則建立該目錄)

gen.excel.path=D:/**/**.xlsx
gen.target.path=D:/**/**.xml