A General Method for Java Parsing excel--Advanced Edition

Posted by souravsasi123 on Fri, 06 Sep 2019 05:30:19 +0200

Ask questions

Through previous research on parsing excel in java, it was found that the parsing of Excel in some complex formats could not be satisfied, such as

The excel of this format cannot be parsed using the previous method, so how should we parse Excel for this complex format?

Analytical problems

We studied the relationship of this complex format row through the debug test and found that although the first four rows were merged like user name, password, and role.But when parsing, they are placed in the first line by default, like wk25, which is also the default in the first line, but like Monday and Tuesday, you might think it should be the default in the second line, but not because wk25 combines the results of the first two lines, so Monday and Tuesday are the default in the third line.When it comes to this, you should understand his rules, so we've used improvements to the configuration file and modifications to the partial parsing code to solve this problem.

Solve the problem

First let's see what changes have been made to the configuration file

Detailed comments in the picture are not explained here, but the generic version of the resolveEntity tag is the corresponding generic version of the entity tag, which is renamed here to distinguish between parsing and exporting

Let's still look directly at the code, which has detailed comments

 /**
     * Resolve excel
     *
     * @param multipartFile File Stream
     * @param savePath      Path where files are stored in the project
     * @param t             Refers to the type of entity in the returned collection
     * @param jsonResult    Result Information
     * @return Parse Set
     */
    private List<T> resolveExcel(MultipartFile multipartFile, String savePath, T t, JsonResult jsonResult) throws Exception {
        List<T> list = new ArrayList<>();
        //1. Create Reader Objects
        SAXReader reader = new SAXReader();
        //2. Load xml 
 Document document=reader.read(Objects.requireNonNull(ExcelUtils.class.getClassLoader().getResource("ExcelUtils.xml")).getPath());
        //Get the root element, entitys
        Element rootElement = document.getRootElement();
        //Get the child element of the root element, entity
        List<Element> elements = rootElement.elements();
        Class classes = t.getClass();
        for (Element element : elements) {
            if ("resolveEntity".equals(element.getName()) && classes.getSimpleName().equals(element.attributeValue("value"))) {
                //Get the child element column of entity
                List<Element> elementList = element.elements();
               //Create local test file
                File file = new File("E:\\user.xls");
                //The following notes describe how to use the Utils using the MultipartFile file received in the actual project
//                String[] split = multipartFile.getName().split("\\.");
                String[] split = file.getName().split("\\.");
                Workbook wb = null;
                if ("xls".equals(split[1])) {
                    //The following notes describe how to use the Utils using the MultipartFile file received in the actual project
//                    InputStream fis = multipartFile.getInputStream();
                    InputStream fis = new FileInputStream(file);
                    wb = new HSSFWorkbook(fis);
                } else if ("xlsx".endsWith(file.getName())) {
                    //The following notes describe how to use the Utils using the MultipartFile file received in the actual project
//                    wb = new XSSFWorkbook((File) multipartFile);
                    wb = new XSSFWorkbook(file);
                } else {
                    jsonResult.setFailReason("File format error");
                }
                Sheet sheet = wb.getSheetAt(0);
                //The first line here is the startRow we configured in the resolveEntity tag
                int fistRowNumber = Integer.parseInt(element.attributeValue("startRow"));
                //Get the last line
                int lastRowNumber = sheet.getLastRowNum();
                //Traverse all rows
                for (int rIndex = fistRowNumber; rIndex <= lastRowNumber; rIndex++) {
                    //Instantiate an entity to store data obtained by traversing excel
                    t = (T) classes.newInstance();
                    //Get Rows
                    Row row = sheet.getRow(rIndex);
                    int rowCount = 0;
                    //Create a map to temporarily store data and assign it to the map field in entity
                    Map<String, String> map = new HashMap<>();
                    Field mapFiled = null;
                    if (row != null) {
                        //Start from the first column by default
                        int cel = 0;
                        while (true) {
                            //Determine whether the data in rows and columns is empty
                            if (row.getCell(cel) != null) {
                                //Traversing labels in column in xml
                                for (Element element1 : elementList) {
                                    //If the corresponding cel is equal to the column currently being parsed and the number of rows is greater than or equal to the startRow we configured in the column tag in the configuration file, that is, when the current number of rows is greater than or equal to the number of starting rows from which the field begins to be assigned
                                    if ("column".equals(element1.getName()) &&        Integer.parseInt(element1.attributeValue("cel")) - 1 == cel && Integer.parseInt(element1.attributeValue("startRow"))-1 <= rIndex) {
                                        //Get all the properties of this class
                                        Field[] fields = classes.getDeclaredFields();
                                        //traversal attributes
                                        for (Field field : fields) {
                                            //Assign a value if the cel corresponding value exists in the entity
                                            if (element1.attributeValue("value").equals(field.getName()) ) {
                                                field.setAccessible(true);
                                                //Assign a value to entity, if it is a date type get the corresponding date format
                                                conversionType(field,row.getCell(cel).toString(),t,element.attributeValue("dateForMate"));
                                                rowCount++;
                                            }
                                        }
                                        //Get the parent of the incoming entity
                                        Class clazz = classes.getSuperclass();
                                        //If there is a parent
                                        while(clazz  != null){
                                            //Get all the attributes of the parent class
                                            Field[] supFiles = clazz.getDeclaredFields();
                                            for (Field field : supFiles) {
                                                //Assign a value if the cel corresponding value exists in the entity
                                                if (element1.attributeValue("value").equals(field.getName())) {
                                                    field.setAccessible(true);
                                                    //Assigning values to entity
                                               conversionType(field,row.getCell(cel).toString(),t, element.attributeValue("dateForMate"));
                                                    rowCount++;
                                                    break;
                                                }
                                            }
                                            //Continue to get parent class
                                            clazz = clazz.getSuperclass();
                                        }
                                        //If the current label is a map label
                                    } else if ("map".equals(element1.getName())) {
                                        //Get the corresponding property name in entity
                                        String value = element1.attributeValue("name");
                                        //Get the word label for the map label
                                        List<Element> mapElements = element1.elements();
                                        //Get this property by reflection
                                         mapFiled = classes.getDeclaredField(value);
                                         //If there are subtags
                                        if(mapElements.size() > 0){
                                            for (Element element2 : mapElements) {
                                                if(element2.attributeValue("cel")!=null&&element2.attributeValue("startRow")!=null){
                                                    //Determines whether the current column is the same as the configured column and whether the current number of rows is greater than or equal to the configured starting number of rows
                                                    if("column".equals(element2.getName())&&Integer.parseInt(element2.attributeValue("cel")) - 1 == cel && Integer.parseInt(element2.attributeValue("startRow"))-1 <= rIndex) {
                                                        //Conditionally, values are built into map s
                                                        map.put(element2.attributeValue("value"), row.getCell(cel).toString());
                                                        rowCount++;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                //Number of columns plus one
                                cel++;
                                //If the current column is empty and is larger than the last column, and rowCount > 0 represents an assignment of map
                            } else if (cel >= row.getLastCellNum() && rowCount > 0) {
                                if(map.size() > 0 && mapFiled != null){
                                    mapFiled.setAccessible(true);
                                    mapFiled.set(t, map);
                                }
                                //Add entity to list
                                list.add(t);
                                break;
                                //If the current column is empty and larger than the last column, and rowCount = 0 has no map assignment
                            }else if(cel >= row.getLastCellNum() && rowCount == 0){
                                break;
                            }
                        }
                    }
                }
            }
        }
        return list;
    }
/**
* Determine what type entity attributes are (basic types can only be determined)
*
* @param field      Current Properties
* @param value      Value of current property
* @param t          In entity
* @param dateFormat If there is a date format for the date type
*/
private void conversionType(Field field, String value, T t, String dateFormat) throws Exception {
    //Or get the type of the property
    Type genericType = field.getGenericType();
    if (genericType.toString().endsWith("String")) {
        field.set(t, value);
    } else if (genericType.toString().endsWith("int") || "java.lang.Integer".equals(genericType.getTypeName())) {
        field.set(t, Integer.parseInt(value));
    } else if ("Long".endsWith(genericType.toString()) || "long".endsWith(genericType.toString())) {
        field.set(t, new Long(value));
    } else if ("char".endsWith(genericType.toString())) {
        field.set(t, value.charAt(0));
    } else if ("boolean".endsWith(genericType.toString()) || "java.lang.Boolean".equals(genericType.getTypeName())) {
        field.set(t, Boolean.valueOf(value));
    } else if ("double".endsWith(genericType.toString()) || "java.lang.Double".equals(genericType.getTypeName())) {
        field.set(t, Double.valueOf(value));
    } else if ("float".endsWith(genericType.toString()) || "java.lang.Float".equals(genericType.getTypeName())) {
        field.set(t, Float.valueOf(value));
    } else if ("java.util.Date".equals(genericType.getTypeName())) {
        field.set(t, new SimpleDateFormat(dateFormat).parse(value));
    }
}

Next let's take a look at the excel that was previously mentioned

Here is the test code

Here's the output from our console

Here we only configure Monday and Tuesday for testing, so you can configure them all for testing.

summary

1. Modify entity label to resolveEntity

2. Add map labels to map map map type fields in entity

3. Add the tag attribute startRow to determine which line to start parsing and assigning

   Through the above answers, I believe you have clearly understood how we can use a general utils to resolve complex excel. Of course, there may still be some complex excels that can not be resolved. After the discovery of the small edition, it will continue to be studied and updated. If the text does not understand, please read the normal edition first and then come back to read it.The scale will be clear. Here we post a link to the normal version, http://www.lindasoft.com/view/article/details?articleId=603

Topics: Excel Java xml Attribute