Статьи

Вставьте контент с помощью Apache POI

вступление

Все знают POI! Это лучшая библиотека для создания документов Excel на Java. это действительно хорошо и может многое сделать легко. Но недавно я хотел сделать что-то не так просто. Я хотел использовать существующий файл xlsx в качестве шаблона и вставить в него некоторые данные. В этом посте я покажу, почему с версией 4.0.0 было не так просто.

Доступные инструменты

Чтобы вставить некоторое содержимое в середину существующего документа Excel, все строки от точки вставки до последней строки должны быть сдвинуты вниз на n строк, где n — количество вставляемых строк. Также предпочтительно сохранять форматирование перемещаемых строк.

На самом деле POI имеет некоторый API, чтобы помочь с этими проблемами.
Интерфейс листа имеет метод
Sheet.shiftRows (int, int, int), который можно использовать так:

sheet.shiftRows (insertPosition, sheet.getLastRowNum (), n);

Есть более продвинутый метод
Sheet.shiftRows (int, int, int, boolean, boolean), но для XSSF логические параметры не имеют значения, как я мог найти в коде. Для HSSF эти параметры могут быть важны.

Так что этот метод должен сделать свое дело! В чем проблема?

проблема

Когда я попытался использовать этот метод, я столкнулся с ужасной проблемой: «Мы обнаружили проблему с некоторым контентом…»

Apache POI

На самом деле это было очень сложно. Я быстро обнаружил, что каким-то образом строки были перемещены неправильно. LibreOffice смог по крайней мере открыть файл, но форматирование и вставленное содержимое были неверными.

Решение

Это заняло 2-3 часа усердного копания :-). Как оказалось, POI даже в последней версии 4.0.0 (скорее всего, даже в 4.0.1) содержит ошибку и не может правильно перемещать строки. Вот ссылка на ошибку:

https://bz.apache.org/bugzilla/show_bug.cgi?id=57423

Метод обновляет ссылки на строки в листе xml, например

<row r = ” 139

но не обновляет ссылки на ячейки

<cr = ” A138 ” s = ”1 ″ /> — неправильно

Ячейка должна указывать на строку верхнего уровня, в этом случае она должна указывать на строку 139 следующим образом:
<cr = ” A139 ” s = ”1 ″ /> — справа

(вы можете взглянуть на лист xml, если распакуете файл xlsx)

Ошибка показывает обходной путь. Я создал метод, который реализует сдвиг и обходной путь в одном методе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void xssfShiftRows(Sheet sh, int firstRow, int last    Row, int shiftN) {
    int firstShiftedRow = firstRow + shiftN;
    int lastShiftedRow = lastRow + shiftN;
    sh.shiftRows(firstRow, lastRow, shiftN, true, true);
    /*
     * This code is a workaround for the bug
     * In the sheet xml the row references are updated like this:
     * <row r="139"
     * but the cell references are incorrect
     * <c r="A138" s="1"/>
     *
     * The number in the row 139 must match the number in the cell A139.
     * This code manually updates these links.
     */
               for (int nRow = firstShiftedRow; nRow <= lastShiftedRow; nRow++)  {
    final Row row = sh.getRow(nRow);
    if (row != null) {
    String msg = "Row[rownum=" + row.getRowNum()
    + "] contains cell(s) included in a multi-cell array         formula.  "
    + "You cannot change part of an array.";
    for (Cell c : row) {
        ((XSSFCell) c).updateCellReferencesForShifting(msg);
    }
  }
}
}

Опубликовано на Java Code Geeks с разрешения Вадима Коркина, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Вставьте контент с помощью Apache POI

Мнения, высказанные участниками Java Code Geeks, являются их собственными.