java - 在 Java 中使用 SAX 解析检测 'Inline String' 单元格值时出现问题

标签 java excel apache-poi saxparser

我有一个巨大的 Excel 文件,我正在尝试使用 JAVA 中的 SAX 解析器对其进行解析。我主要使用 Apache POI 库并处理 .XLSX 文件。以下是我正在尝试读取的 /xl/worksheets/sheet1.xml 压缩 excel 文件夹中 xml 内容的外观:

<row r="1">
<c r="A1" t="inlineStr"><is><t>my value 1</t></is></c>
<c r="B1" t="inlineStr"><is><t>my value 2</t></is></c>
<c r="C1" t="inlineStr"><is><t>my value 3</t></is></c>
</row>

这个特定的 Excel 文件正在使用内联字符串值,如上所示。

这是我的函数,它执行程序来读取文件:

public void executeExcelDataExtraction() throws IOException, OpenXML4JException, SAXException, ParserConfigurationException, XMLStreamException, FactoryConfigurationError {
    OPCPackage pkg = OPCPackage.open(XLSX_INPUT_FILE.xlsx);
    XSSFReader r = new XSSFReader( pkg );
    SharedStringsTable sst = r.getSharedStringsTable();
    ImportArticleDataProcessorExcelFileReaderFactory handlerFactory = new 
         ImportArticleDataProcessorExcelFileReaderFactory(sst);
    XMLReader parser = fetchSheetParser(handlerFactory);
    Iterator<InputStream> sheets = r.getSheetsData();
    if (sheets instanceof XSSFReader.SheetIterator) {
        XSSFReader.SheetIterator sheetiterator = 
             (XSSFReader.SheetIterator)sheets;
        while(sheetiterator.hasNext()) {
            System.out.println("Processing new sheet:\n");
            InputStream sheet = sheets.next();
            InputSource sheetSource = new InputSource(sheet);
            parser.parse(sheetSource);
            rowCache = handlerFactory.getRowCache();
            sheet.close();
            pkg.close();
            if(!rowCache.isEmpty()) 
                createCategoryMap(rowCache);                
        }
    }
}

这是我的工作表处理程序工厂类,用于上面的函数。

import java.util.LinkedList;
import java.util.List;

import org.xml.sax.Attributes;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class ImportArticleDataProcessorExcelFileReaderFactory extends DefaultHandler{

    private static final String ROW_EVENT = "row";
    private static final String CELL_EVENT = "c";
    private SharedStringsTable sst;
    private String lastContents;
    private boolean nextIsString;
    private List<String> cellCache = new LinkedList<>();
    private List<String[]> rowCache = new LinkedList<>();

    ImportArticleDataProcessorExcelFileReaderFactory(SharedStringsTable sst) {
        this.sst = sst;
    }

    public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {
        // c => cell
        if (CELL_EVENT.equals(name)) {
            String cellType = attributes.getValue("t");
            if(cellType != null && cellType.equals("s")) {
                nextIsString = true;
            } else {
                nextIsString = false;
            }
        } else if (ROW_EVENT.equals(name)) {
            if (!cellCache.isEmpty()) {
                rowCache.add(cellCache.toArray(new String[cellCache.size()]));
            }
            cellCache.clear();
        }
        lastContents = "";
    }

    public void endElement(String uri, String localName, String name)
            throws SAXException {
        // Process the last contents as required.
        // Do now, as characters() may be called more than once
        if(nextIsString) {
            int idx = Integer.parseInt(lastContents);
            lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
            nextIsString = false;
        }

        // v => contents of a cell
        // Output after we've seen the string contents
        if(name.equals("v")) {
            cellCache.add(lastContents.trim());
        }
    }

    public void characters(char[] ch, int start, int length)
            throws SAXException {
        lastContents += new String(ch, start, length);
    }

    public List<String[]> getRowCache() {
        return rowCache;
    }

}

所有其他不具有内联字符串的 Excel 文件都能够成功读取,但是对于内部具有内联字符串的文件,该算法仅读取 cellType=inlineStr 但永远不会获取正确的值。

我想要什么:

我想要的只是打印位于内联字符串单元格内的值,例如就我而言,它是“我的值(value) 1”、“我的值(value) 2”和“我的值(value) 3”

最佳答案

如果有人正在寻找类似的解决方案,只是想让您知道我已经通过在上面的 ImportArticleDataProcessorExcelFileReaderFactory 类中添加以下几行来解决它:

public void startElement(String uri, String localName, String name){

        // rest of the code...

        inlineStr = false;
        if(cellType != null && cellType.equals("inlineStr")) {
            inlineStr = true;
        } 
        ...
}

public void endElement(String uri, String localName, String name){

        // rest of the code...

       if(name.equals("t") && inlineStr) {
          cellCache.add(lastContents.trim());
       }
       ...
}
上述工厂类中的

void strings 函数正确识别单元格的内容,并且我的答案中给出的更改成功使用内联字符串单元格中的所有值填充 cellCache 列表.

请引用上面评论中@Axel的答案,并按照此答案获取来源:How to check a number in a string contains a date and exponential numbers while parsing excel file using apache event model in java

关于java - 在 Java 中使用 SAX 解析检测 'Inline String' 单元格值时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56597082/

相关文章:

java - 使用 jxl 读取 Excel 工作表无法超过 255 行

java - Apache POI - 文本长度限制为 8 或 10

java - 如何摆脱 Java Web 服务器 url 中的目录前缀?

java - QBit POST 方法无法解析明文

excel - 如何在 Calc(或 Excel)上定义动态范围?

java - HSSFRichTextString 样式不适用于具有默认值的单元格

java - Spring MVC + jquery 对于大请求数据绑定(bind) null

java - 使用 Log4J 1.*,如何将两个包写入两个单独的文件?

vba - 删除名称以特定值开头的工作表

vba - 复制并粘贴值而不是公式