我正在使用apache POI 3.7。我试图替换word文档(docx)中的表列的值。但是,我所做的是它不断追加文档中当前值的值。但是,如果表列值为null,则将值放置。你能告诉我一些如何解决这个问题的想法。下面是我到目前为止所做的代码。
提前致谢。
package test.doc;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
public class POIDocXTableTest {
public static void main(String[] args)throws IOException {
String fileName = "C:\\Test.docx";
InputStream fis = new FileInputStream(fileName);
XWPFDocument document = new XWPFDocument(fis);
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (int x=0; x<paragraphs.size();x++)
{
XWPFParagraph paragraph = paragraphs.get(x);
System.out.println(paragraph.getParagraphText());
}
List<XWPFTable> tables = document.getTables();
for (int x=0; x<tables.size();x++)
{
XWPFTable table = tables.get(x);
List<XWPFTableRow> tableRows = table.getRows();
tableRows.remove(x);
for (int r=0; r<tableRows.size();r++)
{
System.out.println("Row "+ (r+1)+ ":");
XWPFTableRow tableRow = tableRows.get(r);
List<XWPFTableCell> tableCells = tableRow.getTableCells();
for (int c=0; c<tableCells.size();c++)
{
System.out.print("Column "+ (c+1)+ ": ");
XWPFTableCell tableCell = tableCells.get(c);
//tableCell.setText("TAE");
String tableCellVal = tableCell.getText();
if ((c+1)==2){
if (tableCellVal!=null){
if (tableCellVal.length()>0){
char c1 = tableCellVal.charAt(0);
String s2 = "-TEST";
char c2 = s2.charAt(0);
String test = tableCell.getText().replace(tableCellVal,s2);
tableCell.setText(test);
}else{
//tableCell.setText("NULL");
}
}
}
System.out.println("tableCell.getText(" + (c) + "):" + tableCellVal);
}
}
System.out.println("\n");
}
OutputStream out = new FileOutputStream(fileName);
document.write(out);
out.close();
}
}
答案 0 :(得分:6)
防止段落样式和查找具有不同样式的搜索字符串的最佳解决方案是此方法:
private long replaceInParagraphs(Map<String, String> replacements, List<XWPFParagraph> xwpfParagraphs) {
long count = 0;
for (XWPFParagraph paragraph : xwpfParagraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (Map.Entry<String, String> replPair : replacements.entrySet()) {
String find = replPair.getKey();
String repl = replPair.getValue();
TextSegement found = paragraph.searchText(find, new PositionInParagraph());
if ( found != null ) {
count++;
if ( found.getBeginRun() == found.getEndRun() ) {
// whole search string is in one Run
XWPFRun run = runs.get(found.getBeginRun());
String runText = run.getText(run.getTextPosition());
String replaced = runText.replace(find, repl);
run.setText(replaced, 0);
} else {
// The search string spans over more than one Run
// Put the Strings together
StringBuilder b = new StringBuilder();
for (int runPos = found.getBeginRun(); runPos <= found.getEndRun(); runPos++) {
XWPFRun run = runs.get(runPos);
b.append(run.getText(run.getTextPosition()));
}
String connectedRuns = b.toString();
String replaced = connectedRuns.replace(find, repl);
// The first Run receives the replaced String of all connected Runs
XWPFRun partOne = runs.get(found.getBeginRun());
partOne.setText(replaced, 0);
// Removing the text in the other Runs.
for (int runPos = found.getBeginRun()+1; runPos <= found.getEndRun(); runPos++) {
XWPFRun partNext = runs.get(runPos);
partNext.setText("", 0);
}
}
}
}
}
return count;
}
此方法适用于跨越多个Run的搜索字符串。被替换的部分从第一个找到的Run获得样式。
答案 1 :(得分:3)
好吧,我做过类似的事情,用指定的单词替换单词模板中的标记......:
public DotxTemplateFiller() {
String filename = "/poi/ls_Template_modern_de.dotx";
String outputPath = "/poi/output/output" + new Date().getTime()
+ ".dotx";
OutputStream out = null;
try {
File file = new File(filename);
XWPFDocument template = new XWPFDocument(new FileInputStream(file));
List<XWPFParagraph> xwpfParagraphs = template.getParagraphs();
replaceInParagraphs(xwpfParagraphs);
List<XWPFTable> tables = template.getTables();
for (XWPFTable xwpfTable : tables) {
List<XWPFTableRow> tableRows = xwpfTable.getRows();
for (XWPFTableRow xwpfTableRow : tableRows) {
List<XWPFTableCell> tableCells = xwpfTableRow
.getTableCells();
for (XWPFTableCell xwpfTableCell : tableCells) {
xwpfParagraphs = xwpfTableCell.getParagraphs();
replaceInParagraphs(xwpfParagraphs);
}
}
}
out = new FileOutputStream(new File(outputPath));
template.write(out);
out.flush();
out.close();
//System.exit(0);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
// nothing to do ....
}
}
}
}
/**
* @param xwpfParagraphs
*/
private void replaceInParagraphs(List<XWPFParagraph> xwpfParagraphs) {
for (XWPFParagraph xwpfParagraph : xwpfParagraphs) {
List<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();
for (XWPFRun xwpfRun : xwpfRuns) {
String xwpfRunText = xwpfRun.getText(xwpfRun
.getTextPosition());
for (Map.Entry<String, String> entry : replacements
.entrySet()) {
if (xwpfRunText != null
&& xwpfRunText.contains(entry.getKey())) {
xwpfRunText = xwpfRunText.replaceAll(
entry.getKey(), entry.getValue());
}
}
xwpfRun.setText(xwpfRunText, 0);
}
}
}
public static void main(String[] args) {
new DotxTemplateFiller();
}
首先,我为MS Word模板中的常规段落和表格单元格中的段落执行了此操作。 希望它对你有所帮助,我希望我理解你的问题......: - )
祝福。
答案 2 :(得分:0)
添加到Josh's解决方案后,我正在构建的地图最终带有一千多个标签,并且还在继续增长。为了减少处理,我决定构建一个我知道在段落中出现的标签的小子集,通常最后只包含一个或两个标签的映射,然后将其作为映射传递给 replaceInParagraphs < / strong>方法。另外,使用Substitution对象存储替换文本,允许我将方法添加到该对象中(例如格式化),替换完成后可以调用该方法。使用子集Map还可以让我知道在任何段落中进行了哪些替换。
private Map<String, Substitution> buildTagList(Map<String, Substitution> replacements, List<XWPFParagraph> xwpfParagraphs, String start, String end) {
Map<String, Substitution> returnMap = new HashMap<String, Substitution> ();
for (XWPFParagraph paragraph : xwpfParagraphs) {
List<XWPFRun> runs = paragraph.getRuns();
// Check is there is a tag in the paragraph
TextSegment found = paragraph.searchText(start, new PositionInParagraph());
String runText = "";
XWPFRun run = null;
if ( found != null ) {
StringBuilder b = new StringBuilder();
for (int runPos = found.getBeginRun(); runPos < runs.size(); runPos++) {
run = runs.get(runPos);
b.append(run.getText(run.getTextPosition()));
runText = b.toString();
}
// Now we need to find all tags in the run
boolean finished = false;
int tagStart = 0;
int tagEnd = 0;
while ( ! finished ) {
// get the first tag
tagStart = runText.indexOf(start,tagStart);
tagEnd = runText.indexOf(end, tagEnd);
if ( tagStart >= 0 ) {
String tag = runText.substring(tagStart, tagEnd + end.length());
Substitution s = replacements.get(tag);
if (s != null) {
returnMap.putIfAbsent(tag,s);
}
}
else
finished = true;
tagStart = tagEnd + end.length();
tagEnd = tagStart;
}
}
}
return returnMap;
}