Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.junit.jupiter.api.Test;

/**
Expand Down Expand Up @@ -260,6 +261,43 @@ public void dateFormatFill() {
EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(data());
}

/**
* Example for filling a unconventional template.
*/
@Test
public void unconventionalFill() {
String templateFileName =
TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "unconventional.xlsx";
String fileName = TestFileUtil.getPath() + "unconventionalFill" + System.currentTimeMillis() + ".xlsx";

try (ExcelWriter excelWriter =
EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
Map<String, String> map = MapUtils.newHashMap();
map.put("foo", "foo-value");
map.put("bar", "bar-value");
String[] sheetNames = {"merge", "multi", "escape", "empty"};
for (String sheetName : sheetNames) {
excelWriter.fill(map, EasyExcel.writerSheet(sheetName).build());
}

Function<Integer, List<Map<String, String>>> getListMap = size -> {
List<Map<String, String>> listMap = ListUtils.newArrayListWithCapacity(size);
for (int j = 0; j < size; j++) {
Map<String, String> currentMap = MapUtils.newHashMap();
currentMap.put("bar1", "Bar1-" + j);
currentMap.put("bar2", "Bar2-" + j);
currentMap.put("bar3", "Bar3-" + j);
currentMap.put("bar4", "Bar4-" + j);
currentMap.put("bar5", "Bar5-" + j);
listMap.add(currentMap);
}
return listMap;
};
excelWriter.fill(map, EasyExcel.writerSheet("list").build());
excelWriter.fill(getListMap.apply(10), EasyExcel.writerSheet("list").build());
}
}

private List<FillData> data() {
List<FillData> list = ListUtils.newArrayList();
for (int i = 0; i < 10; i++) {
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cn.idev.excel.enums;

/**
* template string part type
*/
public enum TemplateStringPartType {
/**
* Content in plain text.
*/
TEXT,

/**
* Common variable.
*/
COMMON_VARIABLE,

/**
* Collection variable.
*/
COLLECTION_VARIABLE
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cn.idev.excel.context.WriteContext;
import cn.idev.excel.enums.CellDataTypeEnum;
import cn.idev.excel.enums.TemplateStringPartType;
import cn.idev.excel.enums.WriteDirectionEnum;
import cn.idev.excel.enums.WriteTemplateAnalysisCellTypeEnum;
import cn.idev.excel.exception.ExcelGenerateException;
Expand All @@ -15,22 +16,16 @@
import cn.idev.excel.util.PoiUtils;
import cn.idev.excel.util.StringUtils;
import cn.idev.excel.util.WriteHandlerUtils;
import cn.idev.excel.write.handler.TemplateStringParseHandler;
import cn.idev.excel.write.handler.context.CellWriteHandlerContext;
import cn.idev.excel.write.handler.context.RowWriteHandlerContext;
import cn.idev.excel.write.metadata.fill.AnalysisCell;
import cn.idev.excel.write.metadata.fill.FillConfig;
import cn.idev.excel.write.metadata.fill.FillWrapper;
import cn.idev.excel.write.metadata.fill.TemplateStringPart;
import cn.idev.excel.write.metadata.holder.WriteSheetHolder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
Expand All @@ -44,17 +39,8 @@

/**
* Fill the data into excel
*
*
*/
public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {

private static final String ESCAPE_FILL_PREFIX = "\\\\\\{";
private static final String ESCAPE_FILL_SUFFIX = "\\\\\\}";
private static final String FILL_PREFIX = "{";
private static final String FILL_SUFFIX = "}";
private static final char IGNORE_CHAR = '\\';
private static final String COLLECTION_PREFIX = ".";
/**
* Fields to replace in the template
*/
Expand Down Expand Up @@ -83,6 +69,11 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor {
*/
private UniqueDataFlagKey currentUniqueDataFlag;

/**
* The template string parse handler for this fill
*/
private TemplateStringParseHandler currentTemplateStringParseHandler;

public ExcelWriteFillExecutor(WriteContext writeContext) {
super(writeContext);
}
Expand All @@ -109,6 +100,7 @@ public void fill(Object data, FillConfig fillConfig) {
currentDataPrefix = null;
}
currentUniqueDataFlag = uniqueDataFlag(writeContext.writeSheetHolder(), currentDataPrefix);
currentTemplateStringParseHandler = fillConfig.getTemplateStringParseHandler();

// processing data
if (realData instanceof Collection) {
Expand Down Expand Up @@ -510,95 +502,91 @@ private String prepareData(
if (StringUtils.isEmpty(value)) {
return null;
}
StringBuilder preparedData = new StringBuilder();
AnalysisCell analysisCell = null;

int startIndex = 0;
int length = value.length();
int lastPrepareDataIndex = 0;
out:
while (startIndex < length) {
int prefixIndex = value.indexOf(FILL_PREFIX, startIndex);
if (prefixIndex < 0) {
break;
Collection<TemplateStringPart> templateStringParts = currentTemplateStringParseHandler.parse(value);
if (CollectionUtils.isEmpty(templateStringParts)) {
return null;
}
AnalysisCell analysisCell = analysisByTemplateStringParts(value, rowIndex, columnIndex, templateStringParts);
if (analysisCell != null) {
List<String> variableList = analysisCell.getVariableList(),
prepareDataList = analysisCell.getPrepareDataList();
// fix https://github.com/fast-excel/fastexcel/issues/1552
// When read template, XLSX data may be in `is` labels, and set the time set in `v` label, lead to can't set
// up successfully, so all data format to empty first.
if (CollectionUtils.isNotEmpty(variableList)) {
cell.setBlank();
} else if (CollectionUtils.isNotEmpty(prepareDataList)) {
return String.join(StringUtils.EMPTY, analysisCell.getPrepareDataList());
}
if (prefixIndex != 0) {
char prefixPrefixChar = value.charAt(prefixIndex - 1);
if (prefixPrefixChar == IGNORE_CHAR) {
startIndex = prefixIndex + 1;
}
return dealAnalysisCell(analysisCell, rowIndex, firstRowCache);
}

private AnalysisCell analysisByTemplateStringParts(
String value, Integer rowIndex, Integer columnIndex, Collection<TemplateStringPart> templateStringParts) {
List<TemplateStringPart> orderedTemplateStringParts = templateStringParts.stream()
.filter(part -> part != null && part.getType() != null)
.sorted(Comparator.comparing(TemplateStringPart::getOrder, Comparator.nullsLast(Integer::compareTo)))
.collect(Collectors.toList());
AnalysisCell analysisCell = null;
StringBuilder textAppender = new StringBuilder();
int partsSize = orderedTemplateStringParts.size();
for (int i = 0; i < partsSize; i++) {
TemplateStringPart templateStringPart = orderedTemplateStringParts.get(i);
TemplateStringPartType currentPartType = templateStringPart.getType();
boolean tail = i == partsSize - 1;
if (TemplateStringPartType.TEXT == currentPartType) {
textAppender.append(templateStringPart.getText());
if (!tail) {
continue;
}
}
int suffixIndex = -1;
while (suffixIndex == -1 && startIndex < length) {
suffixIndex = value.indexOf(FILL_SUFFIX, startIndex + 1);
if (suffixIndex < 0) {
break out;
String trailingText = textAppender.toString();
if (analysisCell == null) {
if (!trailingText.equals(value)) {
AnalysisCell cell = new AnalysisCell();
cell.setPrepareDataList(Collections.singletonList(trailingText));
return cell;
}
continue;
}
startIndex = suffixIndex + 1;
char prefixSuffixChar = value.charAt(suffixIndex - 1);
if (prefixSuffixChar == IGNORE_CHAR) {
suffixIndex = -1;
analysisCell.getPrepareDataList().add(trailingText);
if (Boolean.TRUE.equals(analysisCell.getOnlyOneVariable()) && !StringUtils.isEmpty(trailingText)) {
analysisCell.setOnlyOneVariable(Boolean.FALSE);
}
continue;
}
if (analysisCell == null) {
analysisCell = initAnalysisCell(rowIndex, columnIndex);
}
String variable = value.substring(prefixIndex + 1, suffixIndex);
if (StringUtils.isEmpty(variable)) {
continue;
String previousText = textAppender.toString();
analysisCell.getPrepareDataList().add(previousText);
if (textAppender.length() > 0) {
textAppender.setLength(0);
}
int collectPrefixIndex = variable.indexOf(COLLECTION_PREFIX);
if (collectPrefixIndex > -1) {
if (collectPrefixIndex != 0) {
analysisCell.setPrefix(variable.substring(0, collectPrefixIndex));
}
variable = variable.substring(collectPrefixIndex + 1);
if (StringUtils.isEmpty(variable)) {
continue;
}
analysisCell.setCellType(WriteTemplateAnalysisCellTypeEnum.COLLECTION);
if (tail) {
analysisCell.getPrepareDataList().add(textAppender.toString());
}
analysisCell.getVariableList().add(variable);
if (lastPrepareDataIndex == prefixIndex) {
analysisCell.getPrepareDataList().add(StringUtils.EMPTY);
// fix https://github.com/fast-excel/fastexcel/issues/2035
if (lastPrepareDataIndex != 0) {
analysisCell.setOnlyOneVariable(Boolean.FALSE);
}
} else {
String data = convertPrepareData(value.substring(lastPrepareDataIndex, prefixIndex));
preparedData.append(data);
analysisCell.getPrepareDataList().add(data);
List<String> variableList = analysisCell.getVariableList();
if (Boolean.TRUE.equals(analysisCell.getOnlyOneVariable())
&& (!variableList.isEmpty() || !StringUtils.isEmpty(previousText))) {
analysisCell.setOnlyOneVariable(Boolean.FALSE);
}
lastPrepareDataIndex = suffixIndex + 1;
}
// fix https://github.com/fast-excel/fastexcel/issues/1552
// When read template, XLSX data may be in `is` labels, and set the time set in `v` label, lead to can't set
// up successfully, so all data format to empty first.
if (analysisCell != null && CollectionUtils.isNotEmpty(analysisCell.getVariableList())) {
cell.setBlank();
if (TemplateStringPartType.COMMON_VARIABLE.equals(currentPartType)) {
variableList.add(templateStringPart.getVariableName());
analysisCell.setCellType(WriteTemplateAnalysisCellTypeEnum.COMMON);
continue;
}
variableList.add(templateStringPart.getVariableName());
analysisCell.setCellType(WriteTemplateAnalysisCellTypeEnum.COLLECTION);
String collectionName = templateStringPart.getCollectionName();
analysisCell.setPrefix(StringUtils.isEmpty(collectionName) ? null : collectionName);
}
return dealAnalysisCell(
analysisCell, value, rowIndex, lastPrepareDataIndex, length, firstRowCache, preparedData);
return analysisCell;
}

private String dealAnalysisCell(
AnalysisCell analysisCell,
String value,
int rowIndex,
int lastPrepareDataIndex,
int length,
Map<UniqueDataFlagKey, Set<Integer>> firstRowCache,
StringBuilder preparedData) {
AnalysisCell analysisCell, int rowIndex, Map<UniqueDataFlagKey, Set<Integer>> firstRowCache) {
if (analysisCell != null) {
if (lastPrepareDataIndex == length) {
analysisCell.getPrepareDataList().add(StringUtils.EMPTY);
} else {
analysisCell.getPrepareDataList().add(convertPrepareData(value.substring(lastPrepareDataIndex)));
analysisCell.setOnlyOneVariable(Boolean.FALSE);
}
UniqueDataFlagKey uniqueDataFlag =
uniqueDataFlag(writeContext.writeSheetHolder(), analysisCell.getPrefix());
if (WriteTemplateAnalysisCellTypeEnum.COMMON.equals(analysisCell.getCellType())) {
Expand All @@ -619,7 +607,12 @@ private String dealAnalysisCell(

collectionAnalysisCellList.add(analysisCell);
}
return preparedData.toString();
List<String> prepareDataList = analysisCell.getPrepareDataList();
return String.join(
StringUtils.EMPTY,
prepareDataList.size() > 1
? prepareDataList.subList(0, prepareDataList.size() - 1)
: prepareDataList);
}
return null;
}
Expand All @@ -638,12 +631,6 @@ private AnalysisCell initAnalysisCell(Integer rowIndex, Integer columnIndex) {
return analysisCell;
}

private String convertPrepareData(String prepareData) {
prepareData = prepareData.replaceAll(ESCAPE_FILL_PREFIX, FILL_PREFIX);
prepareData = prepareData.replaceAll(ESCAPE_FILL_SUFFIX, FILL_SUFFIX);
return prepareData;
}

private UniqueDataFlagKey uniqueDataFlag(WriteSheetHolder writeSheetHolder, String wrapperName) {
return new UniqueDataFlagKey(writeSheetHolder.getSheetNo(), writeSheetHolder.getSheetName(), wrapperName);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cn.idev.excel.write.handler;

import cn.idev.excel.write.metadata.fill.TemplateStringPart;
import java.util.Collection;

/**
* Template string parse handler
*/
public interface TemplateStringParseHandler {
/**
* Parse the template string
*
* @param stringValue String value
* @return The multi parts formed after parsing a template string
*/
Collection<TemplateStringPart> parse(String stringValue);
}
Loading