Replace table column value in Apache POI

2019-02-26 01:14发布

问题:

I am using apache POI 3.7. I am trying to replace the value of a table column in a word document (docx). However, what I have done is it keeps appending the value of the current value in the document. But if a table column value is null, it places the value. Can you give me some thoughts how to resolve this. Below is the code I have done so far.

Thanks in advance.

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();
    }
}

回答1:

The best solution to prevent styles in paragraphs and find search strings with different styles is this method:

  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;
  }

This method works with search strings spanning over more than one Run. The replaced part gets the style from the first found Run.



回答2:

well, I have done something like that, to replace marks in a word template by specified words...:

    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();
}

First I did it for regular paragraphs in the MS Word template and than for paragraphs inside table cells. Hope it is helpful for you and I hope I understood your problem right... :-)

Best wishes.