В данной статье описывается как скопировать часть текстового docx файла в другой docx файл, с сохранением используемых стилей. Задача кажется тривиальной, но на практике возникли некоторые трудности.
Итак, предположим, есть большой docx файл, состоящий из логически разделенных частей, разделенных, скажем, разрывом страницы (Ctrl+Enter). Требуется создать на каждый такой кусок отдельный файл, с сохранением форматирования текста.
Воспользуемся библиотекой Apache POI для разбора файла. Для этого создадим проект и добавим в зависимости POI 3.8. Версия 3.7 не подходит по причине того, что в ней нет возможности перенести стили из одного документа в другой.
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.8</version>
</dependency>
И собственно код для разбора и создания документов:
XWPFDocument doc = new XWPFDocument(new FileInputStream("/home/username/test.docx"));
List<XWPFParagraph> list = doc.getParagraphs();
XWPFDocument tmp = new XWPFDocument();
tmp.createStyles();
String fileName = "test";
boolean isNew = true;
for (XWPFParagraph p : list) {
XWPFStyles style = tmp.getStyles();
if (p.getStyleID() != null && !style.styleExist(p.getStyleID())) {
style.addStyle(doc.getStyles().getStyle(p.getStyle()));
}
// формируем имя файла из первых символов
if (isNew || StringUtils.isBlank(fileName)) {
fileName = p.getParagraphText().trim();
if (fileName.length() > 100) {
fileName = StringUtils.left(fileName, 50);
}
}
XWPFParagraph tmpParagraph = tmp.createParagraph();
tmpParagraph.setStyle(p.getStyle());
isNew = false;
for (XWPFRun r : p.getRuns()) {
XWPFRun tmpRun = tmpParagraph.createRun();
tmpRun.setTextPosition(r.getTextPosition());
// важно использовать именно метод toString() поскольку
// этот метод сохраняет возможные символы "\n", которые getText обрезает
tmpRun.setText(r.toString());
tmpRun.setBold(r.isBold());
tmpRun.setFontFamily(r.getFontFamily());
tmpRun.setFontSize(r.getFontSize());
tmpRun.setItalic(r.isItalic());
tmpRun.setStrike(r.isStrike());
tmpRun.setSubscript(r.getSubscript());
tmpRun.setUnderline(r.getUnderline());
// метод isPageBreak всегда возвращает false,
// независимо от того, содержится ли разрыв страницы в параграфе или нет
// так что используем грязный хак
p.setPageBreak(r.getCTR().toString().contains("<w:br w:type=\"page\"/>"));
}
if (p.isPageBreak()) {
try {
isNew = true;
tmp.write(new FileOutputStream("/home/username/result/" + fileName + ".docx"));
} catch (IOException e) {
e.printStackTrace();
}
tmp = new XWPFDocument();
// требуется версия POI >= 3.8 чтобы сделать это
tmp.createStyles();
}
}
try {
// сохраним последний кусок в файл
tmp.write(new FileOutputStream("/home/username/result/" + fileName + ".docx"));
} catch (IOException e) {
e.printStackTrace();
}
Комментариев нет:
Отправить комментарий