Browse Source

* 修复部分xlsx无法读取超链接的bug

pull/2533/head
Jiaju Zhuang 3 years ago
parent
commit
61c80a9ff2
  1. 2
      README.md
  2. 46
      easyexcel-core/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java
  3. 25
      easyexcel-core/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java
  4. 5
      easyexcel-core/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java
  5. 8
      easyexcel-core/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java
  6. 6
      easyexcel-core/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java
  7. 44
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataTest.java
  8. BIN
      easyexcel-test/src/test/resources/extra/extraRelationships.xlsx
  9. 4
      pom.xml
  10. 3
      update.md

2
README.md

@ -42,7 +42,7 @@ Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
<version>3.1.1</version>
<exclusions>
<exclusion>
<artifactId>poi-ooxml-schemas</artifactId>

46
easyexcel-core/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java

@ -8,6 +8,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import javax.xml.parsers.ParserConfigurationException;
@ -25,17 +26,23 @@ import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.util.SheetUtils;
import com.alibaba.excel.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
@ -52,6 +59,20 @@ import org.xml.sax.XMLReader;
@Slf4j
public class XlsxSaxAnalyser implements ExcelReadExecutor {
/**
* Storage sheet SharedStrings
*/
public static final PackagePartName SHARED_STRINGS_PART_NAME;
static {
try {
SHARED_STRINGS_PART_NAME = PackagingURIHelper.createPartName("/xl/sharedStrings.xml");
} catch (InvalidFormatException e) {
log.error("Initialize the XlsxSaxAnalyser failure", e);
throw new ExcelAnalysisException("Initialize the XlsxSaxAnalyser failure", e);
}
}
private final XlsxReadContext xlsxReadContext;
private final List<ReadSheet> sheetList;
private final Map<Integer, InputStream> sheetMap;
@ -68,11 +89,9 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
OPCPackage pkg = readOpcPackage(xlsxReadWorkbookHolder, decryptedStream);
xlsxReadWorkbookHolder.setOpcPackage(pkg);
ArrayList<PackagePart> packageParts = pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType());
if (!CollectionUtils.isEmpty(packageParts)) {
PackagePart sharedStringsTablePackagePart = packageParts.get(0);
// Read the Shared information Strings
PackagePart sharedStringsTablePackagePart = pkg.getPart(SHARED_STRINGS_PART_NAME);
if (sharedStringsTablePackagePart != null) {
// Specify default cache
defaultReadCache(xlsxReadWorkbookHolder, sharedStringsTablePackagePart);
@ -89,6 +108,9 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
sheetList = new ArrayList<>();
sheetMap = new HashMap<>();
commentsTableMap = new HashMap<>();
Map<Integer, PackageRelationshipCollection> packageRelationshipCollectionMap = MapUtils.newHashMap();
xlsxReadWorkbookHolder.setPackageRelationshipCollectionMap(packageRelationshipCollectionMap);
XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData();
int index = 0;
if (!ite.hasNext()) {
@ -104,6 +126,20 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor {
commentsTableMap.put(index, commentsTable);
}
}
if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.HYPERLINK)) {
PackageRelationshipCollection packageRelationshipCollection = Optional.ofNullable(ite.getSheetPart())
.map(packagePart -> {
try {
return packagePart.getRelationships();
} catch (InvalidFormatException e) {
log.warn("Reading the Relationship failed", e);
return null;
}
}).orElse(null);
if (packageRelationshipCollection != null) {
packageRelationshipCollectionMap.put(index, packageRelationshipCollection);
}
}
index++;
}
}

25
easyexcel-core/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java

@ -1,5 +1,9 @@
package com.alibaba.excel.analysis.v07.handlers;
import java.util.Optional;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.xml.sax.Attributes;
import com.alibaba.excel.constant.ExcelXmlConstants;
@ -23,13 +27,32 @@ public class HyperlinkTagHandler extends AbstractXlsxTagHandler {
@Override
public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) {
String ref = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_REF);
String location = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_LOCATION);
if (StringUtils.isEmpty(ref)) {
return;
}
// Hyperlink has 2 case:
// case 1,In the 'location' tag
String location = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_LOCATION);
if (location != null) {
CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.HYPERLINK, location, ref);
xlsxReadContext.readSheetHolder().setCellExtra(cellExtra);
xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext);
return;
}
// case 2, In the 'r:id' tag, Then go to 'PackageRelationshipCollection' to get inside
String rId = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_RID);
PackageRelationshipCollection packageRelationshipCollection = xlsxReadContext.xlsxReadSheetHolder()
.getPackageRelationshipCollection();
if (rId == null || packageRelationshipCollection == null) {
return;
}
Optional.ofNullable(packageRelationshipCollection.getRelationshipByID(rId))
.map(PackageRelationship::getTargetURI)
.ifPresent(uri -> {
CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.HYPERLINK, uri.toString(), ref);
xlsxReadContext.readSheetHolder().setCellExtra(cellExtra);
xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext);
});
}
}

5
easyexcel-core/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java

@ -49,6 +49,11 @@ public class ExcelXmlConstants {
*/
public static final String ATTRIBUTE_LOCATION = "location";
/**
* rId attribute
*/
public static final String ATTRIBUTE_RID = "r:id";
/**
* Cell range split
*/

8
easyexcel-core/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java

@ -10,6 +10,7 @@ import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
/**
* sheet holder
@ -36,9 +37,16 @@ public class XlsxReadSheetHolder extends ReadSheetHolder {
* Formula for current label.
*/
private StringBuilder tempFormula;
/**
* excel Relationship
*/
private PackageRelationshipCollection packageRelationshipCollection;
public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) {
super(readSheet, readWorkbookHolder);
this.tagDeque = new LinkedList<String>();
packageRelationshipCollection
= ((XlsxReadWorkbookHolder)readWorkbookHolder).getPackageRelationshipCollectionMap().get(
readSheet.getSheetNo());
}
}

6
easyexcel-core/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java

@ -15,6 +15,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
@ -51,6 +52,11 @@ public class XlsxReadWorkbookHolder extends ReadWorkbookHolder {
*/
private Map<Integer, DataFormatData> dataFormatDataCache;
/**
* excel Relationship, key: sheetNo value: PackageRelationshipCollection
*/
private Map<Integer, PackageRelationshipCollection> packageRelationshipCollectionMap;
public XlsxReadWorkbookHolder(ReadWorkbook readWorkbook) {
super(readWorkbook);
this.saxParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName();

44
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataTest.java

@ -2,6 +2,7 @@ package com.alibaba.easyexcel.test.core.extra;
import java.io.File;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
@ -9,10 +10,13 @@ import org.slf4j.LoggerFactory;
import com.alibaba.easyexcel.test.util.TestFileUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSON;
/**
*
* @author Jiaju Zhuang
*/
public class ExtraDataTest {
@ -20,10 +24,13 @@ public class ExtraDataTest {
private static File file03;
private static File file07;
private static File extraRelationships;
@BeforeClass
public static void init() {
file03 = TestFileUtil.readFile("extra" + File.separator + "extra.xls");
file07 = TestFileUtil.readFile("extra" + File.separator + "extra.xlsx");
extraRelationships = TestFileUtil.readFile("extra" + File.separator + "extraRelationships.xlsx");
}
@Test
@ -36,6 +43,41 @@ public class ExtraDataTest {
read(file03);
}
@Test
public void t03Read() {
EasyExcel.read(extraRelationships, ExtraData.class, new ReadListener() {
@Override
public void invoke(Object data, AnalysisContext context) {
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
@Override
public void extra(CellExtra extra, AnalysisContext context) {
LOGGER.info("extra data:{}", JSON.toJSONString(extra));
switch (extra.getType()) {
case HYPERLINK:
if ("222222222".equals(extra.getText())) {
Assert.assertEquals(1, (int)extra.getRowIndex());
Assert.assertEquals(0, (int)extra.getColumnIndex());
} else if ("333333333333".equals(extra.getText())) {
Assert.assertEquals(1, (int)extra.getRowIndex());
Assert.assertEquals(1, (int)extra.getColumnIndex());
} else {
Assert.fail("Unknown hyperlink!");
}
break;
default:
}
}
})
.extraRead(CellExtraTypeEnum.HYPERLINK)
.sheet()
.doRead();
}
private void read(File file) {
EasyExcel.read(file, ExtraData.class, new ExtraDataListener()).extraRead(CellExtraTypeEnum.COMMENT)
.extraRead(CellExtraTypeEnum.HYPERLINK).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead();

BIN
easyexcel-test/src/test/resources/extra/extraRelationships.xlsx

Binary file not shown.

4
pom.xml

@ -20,7 +20,7 @@
<properties>
<revision>3.1.0</revision>
<revision>3.1.1</revision>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.8</jdk.version>
<gpg.skip>true</gpg.skip>
@ -145,7 +145,7 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

3
update.md

@ -1,3 +1,6 @@
# 3.1.1
* 修复部分xlsx无法读取超链接的bug
# 3.1.0
* 支持jdk17,去除cglib&asm依赖,改成重新拷贝一份 [Issue #2240](https://github.com/alibaba/easyexcel/issues/2240)
* 升级ehcache 到 3.9.9 ,为了兼容jdk17

Loading…
Cancel
Save