com.deepoove.poi.resolver.TemplateResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of poi-tl Show documentation
Show all versions of poi-tl Show documentation
Generate word(docx) with template
/*
* Copyright 2014-2020 Sayi
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.deepoove.poi.resolver;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.xwpf.usermodel.BodyElementType;
import org.apache.poi.xwpf.usermodel.IBodyElement;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFFooter;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.exception.ResolverException;
import com.deepoove.poi.template.BlockTemplate;
import com.deepoove.poi.template.ChartTemplate;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.IterableTemplate;
import com.deepoove.poi.template.MetaTemplate;
import com.deepoove.poi.template.PictureTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import com.deepoove.poi.util.ReflectionUtils;
import com.deepoove.poi.xwpf.CTDrawingWrapper;
import com.deepoove.poi.xwpf.XWPFRunWrapper;
/**
* Resolver
*
* @author Sayi
* @version 1.7.0
*/
public class TemplateResolver extends AbstractResolver {
private static Logger logger = LoggerFactory.getLogger(TemplateResolver.class);
private ElementTemplateFactory elementTemplateFactory;
public TemplateResolver(Configure config) {
this(config, config.getElementTemplateFactory());
}
private TemplateResolver(Configure config, ElementTemplateFactory elementTemplateFactory) {
super(config);
this.elementTemplateFactory = elementTemplateFactory;
}
@Override
public List resolveDocument(XWPFDocument doc) {
List metaTemplates = new ArrayList<>();
if (null == doc) return metaTemplates;
logger.info("Resolve the document start...");
metaTemplates.addAll(resolveBodyElements(doc.getBodyElements()));
metaTemplates.addAll(resolveHeaders(doc.getHeaderList()));
metaTemplates.addAll(resolveFooters(doc.getFooterList()));
logger.info("Resolve the document end, resolve and create {} MetaTemplates.", metaTemplates.size());
return metaTemplates;
}
@Override
public List resolveBodyElements(List bodyElements) {
List metaTemplates = new ArrayList<>();
if (null == bodyElements) return metaTemplates;
// current iterable templates state
Deque stack = new LinkedList();
for (IBodyElement element : bodyElements) {
if (element == null) continue;
if (element.getElementType() == BodyElementType.PARAGRAPH) {
XWPFParagraph paragraph = (XWPFParagraph) element;
new RunningRunParagraph(paragraph, templatePattern).refactorRun();
resolveXWPFRuns(paragraph.getRuns(), metaTemplates, stack);
} else if (element.getElementType() == BodyElementType.TABLE) {
XWPFTable table = (XWPFTable) element;
List rows = table.getRows();
if (null == rows) continue;
for (XWPFTableRow row : rows) {
List cells = row.getTableCells();
if (null == cells) continue;
cells.forEach(cell -> {
addNewMeta(metaTemplates, stack, resolveBodyElements(cell.getBodyElements()));
});
}
}
}
checkStack(stack);
return metaTemplates;
}
@Override
public List resolveXWPFRuns(List runs) {
List metaTemplates = new ArrayList<>();
if (runs == null) return metaTemplates;
Deque stack = new LinkedList();
resolveXWPFRuns(runs, metaTemplates, stack);
checkStack(stack);
return metaTemplates;
}
private void resolveXWPFRuns(List runs, final List metaTemplates,
final Deque stack) {
for (XWPFRun run : runs) {
String text = null;
if (StringUtils.isBlank(text = run.getText(0))) {
// textbox
List visitBodyElements = resolveTextbox(run);
if (!visitBodyElements.isEmpty()) {
addNewMeta(metaTemplates, stack, visitBodyElements);
continue;
}
List pictureTemplates = resolveXWPFPictures(run.getEmbeddedPictures());
if (!pictureTemplates.isEmpty()) {
addNewMeta(metaTemplates, stack, pictureTemplates);
continue;
}
ChartTemplate chartTemplate = resolveXWPFChart(run);
if (null != chartTemplate) {
addNewMeta(metaTemplates, stack, chartTemplate);
continue;
}
continue;
}
RunTemplate runTemplate = (RunTemplate) parseTemplateFactory(text, run, run);
if (null == runTemplate) continue;
char charValue = runTemplate.getSign().charValue();
if (charValue == config.getIterable().getLeft()) {
IterableTemplate freshIterableTemplate = new IterableTemplate(runTemplate);
stack.push(freshIterableTemplate);
} else if (charValue == config.getIterable().getRight()) {
if (stack.isEmpty()) throw new ResolverException(
"Mismatched start/end tags: No start mark found for end mark " + runTemplate);
BlockTemplate latestIterableTemplate = stack.pop();
if (StringUtils.isNotEmpty(runTemplate.getTagName())
&& !latestIterableTemplate.getStartMark().getTagName().equals(runTemplate.getTagName())) {
throw new ResolverException("Mismatched start/end tags: start mark "
+ latestIterableTemplate.getStartMark() + " does not match to end mark " + runTemplate);
}
latestIterableTemplate.setEndMark(runTemplate);
if (latestIterableTemplate instanceof IterableTemplate) {
latestIterableTemplate = ((IterableTemplate) latestIterableTemplate).buildIfInline();
}
addNewMeta(metaTemplates, stack, latestIterableTemplate);
} else {
addNewMeta(metaTemplates, stack, runTemplate);
}
}
}
private ChartTemplate resolveXWPFChart(XWPFRun run) {
CTDrawing ctDrawing = getCTDrawing(run);
if (null == ctDrawing) return null;
CTDrawingWrapper wrapper = new CTDrawingWrapper(ctDrawing);
String title = wrapper.getTitle();
if (null == title) return null;
String rid = wrapper.getCharId();
if (null == rid) return null;
POIXMLDocumentPart documentPart = run.getDocument().getRelationById(rid);
if (null == documentPart || !(documentPart instanceof XWPFChart)) return null;
return (ChartTemplate) parseTemplateFactory(title, (XWPFChart) documentPart, run);
}
private List resolveXWPFPictures(List embeddedPictures) {
List metaTemplates = new ArrayList<>();
if (embeddedPictures == null) return metaTemplates;
for (XWPFPicture pic : embeddedPictures) {
// it's array, to do in the future
CTDrawing ctDrawing = getCTDrawing(pic);
if (null == ctDrawing) continue;
CTDrawingWrapper wrapper = new CTDrawingWrapper(ctDrawing);
String title = wrapper.getTitle();
if (null == title) continue;
PictureTemplate pictureTemplate = (PictureTemplate) parseTemplateFactory(title, pic, null);
if (null != pictureTemplate) metaTemplates.add(pictureTemplate);
}
return metaTemplates;
}
private CTDrawing getCTDrawing(XWPFPicture pic) throws RuntimeException {
XWPFRun run = (XWPFRun) ReflectionUtils.getValue("run", pic);
return getCTDrawing(run);
}
private CTDrawing getCTDrawing(XWPFRun run) {
CTR ctr = run.getCTR();
CTDrawing ctDrawing = CollectionUtils.isNotEmpty(ctr.getDrawingList()) ? ctr.getDrawingArray(0) : null;
return ctDrawing;
}
private void addNewMeta(final List metaTemplates, final Deque stack,
List extends MetaTemplate> newMeta) {
if (stack.isEmpty()) {
metaTemplates.addAll(newMeta);
} else {
stack.peek().getTemplates().addAll(newMeta);
}
}
private void addNewMeta(final List metaTemplates,
final Deque stack, T newMeta) {
if (stack.isEmpty()) {
metaTemplates.add(newMeta);
} else {
stack.peek().getTemplates().add(newMeta);
}
}
private void checkStack(Deque stack) {
if (!stack.isEmpty()) {
throw new ResolverException(
"Mismatched start/end tags: No end iterable mark found for start mark " + stack.peek());
}
}
private List resolveTextbox(XWPFRun run) {
XWPFRunWrapper runWrapper = new XWPFRunWrapper(run);
if (null == runWrapper.getWpstxbx()) return new ArrayList<>();
return resolveBodyElements(runWrapper.getWpstxbx().getBodyElements());
}
List resolveHeaders(List headers) {
List metaTemplates = new ArrayList<>();
if (null == headers) return metaTemplates;
headers.forEach(header -> {
metaTemplates.addAll(resolveBodyElements(header.getBodyElements()));
});
return metaTemplates;
}
List resolveFooters(List footers) {
List metaTemplates = new ArrayList<>();
if (null == footers) return metaTemplates;
footers.forEach(footer -> {
metaTemplates.addAll(resolveBodyElements(footer.getBodyElements()));
});
return metaTemplates;
}
ElementTemplate parseTemplateFactory(String text, Object obj, XWPFRun run) {
if (templatePattern.matcher(text).matches()) {
logger.debug("Resolve where text: {}, and create ElementTemplate for {}", text, obj.getClass());
String tag = gramerPattern.matcher(text).replaceAll("").trim();
if (obj.getClass() == XWPFRun.class) {
return (RunTemplate) elementTemplateFactory.createRunTemplate(tag, (XWPFRun) obj);
} else if (obj.getClass() == XWPFPicture.class) {
return (PictureTemplate) elementTemplateFactory.createPicureTemplate(tag, (XWPFPicture) obj);
} else if (obj.getClass() == XWPFChart.class) {
return (ChartTemplate) elementTemplateFactory.createChartTemplate(tag, (XWPFChart) obj, run);
}
}
return null;
}
}