проблемы определения значений ячеек 'Inline String' с использованием SAX-разбора в Java - PullRequest
0 голосов
/ 14 июня 2019

У меня огромный файл Excel, который я пытаюсь проанализировать с помощью SAX-парсера в JAVA. В основном я использую библиотеку Apache POI и работаю с файлами .XLSX. Вот как выглядит содержимое xml внутри zip-папки excel в /xl/worksheets/sheet1.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, но никогда не получает правильное значение.

Что я хочу:

Все, что мне нужно, это просто напечатать значения, расположенные внутри строковой ячейки, например, в моем случае это «мое значение 1», «мое значение 2» и «мое значение 3»

1 Ответ

0 голосов
/ 14 июня 2019

, если кто-то ищет подобное решение, просто хочу сообщить, что я решил его, добавив несколько строк в мой класс 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 characters функция вышеФабричный класс правильно идентифицирует содержимое ячейки, и мои изменения, как указано в моем ответе, успешно заполняют список cellCache всеми значениями из строковых ячеек.

пожалуйста, обратитесь к ответу @ Axel в комментарии выше и следуйте этому ответудля вашего источника: Как проверить, что число в строке содержит дату и экспоненциальные числа при разборе файла Excel с использованием модели событий apache в java

...