Replacing a text in Apache POI XWPF

前端 未结 10 2204
鱼传尺愫
鱼传尺愫 2020-11-29 18:18

I just found Apache POI library very useful for editing Word files using Java. Specifically, I want to edit a DOCX file using Apache POI\'s XWPF classes. I

10条回答
  •  独厮守ぢ
    2020-11-29 18:52

    Here is what we did for text replacement using Apache POI. We found that it was not worth the hassle and simpler to replace the text of an entire XWPFParagraph instead of a run. A run can be randomly split in the middle of a word as Microsoft Word is in charge of where runs are created within the paragraph of a document. Therefore the text you might be searching for could be half in one run and half in another. Using the full text of a paragraph, removing its existing runs, and adding a new run with the adjusted text seems to solve the problem of text replacement.

    However there is a cost of doing the replacement at the paragraph level; you lose the formatting of the runs in that paragraph. For example if in the middle of your paragraph you had bolded the word "bits", and then when parsing the file you replaced the word "bits" with "bytes", the word "bytes" would no longer be bolded. Because the bolding was stored with a run that was removed when the paragraph's entire body of text was replaced. The attached code has a commented out section that was working for replacement of text at the run level if you need it.

    It should also be noted that the below works if the text you are inserting contains \n return characters. We could not find a way to insert returns without creating a run for each section prior to the return and marking the run addCarriageReturn(). Cheers

        package com.healthpartners.hcss.client.external.word.replacement;
    
    import java.util.List;
    
    import org.apache.commons.lang.StringUtils;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.apache.poi.xwpf.usermodel.XWPFParagraph;
    import org.apache.poi.xwpf.usermodel.XWPFRun;
    
    public class TextReplacer {
        private String searchValue;
        private String replacement;
    
        public TextReplacer(String searchValue, String replacement) {
            this.searchValue = searchValue;
            this.replacement = replacement;
        }
    
        public void replace(XWPFDocument document) {
            List paragraphs = document.getParagraphs();
    
        for (XWPFParagraph xwpfParagraph : paragraphs) {
            replace(xwpfParagraph);
        }
    }
    
    private void replace(XWPFParagraph paragraph) {
        if (hasReplaceableItem(paragraph.getText())) {
            String replacedText = StringUtils.replace(paragraph.getText(), searchValue, replacement);
    
            removeAllRuns(paragraph);
    
            insertReplacementRuns(paragraph, replacedText);
        }
    }
    
    private void insertReplacementRuns(XWPFParagraph paragraph, String replacedText) {
        String[] replacementTextSplitOnCarriageReturn = StringUtils.split(replacedText, "\n");
    
        for (int j = 0; j < replacementTextSplitOnCarriageReturn.length; j++) {
            String part = replacementTextSplitOnCarriageReturn[j];
    
            XWPFRun newRun = paragraph.insertNewRun(j);
            newRun.setText(part);
    
            if (j+1 < replacementTextSplitOnCarriageReturn.length) {
                newRun.addCarriageReturn();
            }
        }       
    }
    
    private void removeAllRuns(XWPFParagraph paragraph) {
        int size = paragraph.getRuns().size();
        for (int i = 0; i < size; i++) {
            paragraph.removeRun(0);
        }
    }
    
    private boolean hasReplaceableItem(String runText) {
        return StringUtils.contains(runText, searchValue);
    }
    
    //REVISIT The below can be removed if Michele tests and approved the above less versatile replacement version
    
    //  private void replace(XWPFParagraph paragraph) {
    //      for (int i = 0; i < paragraph.getRuns().size()  ; i++) {
    //          i = replace(paragraph, i);
    //      }
    //  }
    
    //  private int replace(XWPFParagraph paragraph, int i) {
    //      XWPFRun run = paragraph.getRuns().get(i);
    //      
    //      String runText = run.getText(0);
    //      
    //      if (hasReplaceableItem(runText)) {
    //          return replace(paragraph, i, run);
    //      }
    //      
    //      return i;
    //  }
    
    //  private int replace(XWPFParagraph paragraph, int i, XWPFRun run) {
    //      String runText = run.getCTR().getTArray(0).getStringValue();
    //      
    //      String beforeSuperLong = StringUtils.substring(runText, 0, runText.indexOf(searchValue));
    //      
    //      String[] replacementTextSplitOnCarriageReturn = StringUtils.split(replacement, "\n");
    //      
    //      String afterSuperLong = StringUtils.substring(runText, runText.indexOf(searchValue) + searchValue.length());
    //      
    //      Counter counter = new Counter(i);
    //      
    //      insertNewRun(paragraph, run, counter, beforeSuperLong);
    //      
    //      for (int j = 0; j < replacementTextSplitOnCarriageReturn.length; j++) {
    //          String part = replacementTextSplitOnCarriageReturn[j];
    //
    //          XWPFRun newRun = insertNewRun(paragraph, run, counter, part);
    //          
    //          if (j+1 < replacementTextSplitOnCarriageReturn.length) {
    //              newRun.addCarriageReturn();
    //          }
    //      }
    //      
    //      insertNewRun(paragraph, run, counter, afterSuperLong);
    //      
    //      paragraph.removeRun(counter.getCount());
    //      
    //      return counter.getCount();
    //  }
    
    //  private class Counter {
    //      private int i;
    //      
    //      public Counter(int i) {
    //          this.i = i;
    //      }
    //      
    //      public void increment() {
    //          i++;
    //      }
    //      
    //      public int getCount() {
    //          return i;
    //      }
    //  }
    
    //  private XWPFRun insertNewRun(XWPFParagraph xwpfParagraph, XWPFRun run, Counter counter, String newText) {
    //      XWPFRun newRun = xwpfParagraph.insertNewRun(counter.i);
    //      newRun.getCTR().set(run.getCTR());
    //      newRun.getCTR().getTArray(0).setStringValue(newText);
    //      
    //      counter.increment();
    //      
    //      return newRun;
    //  }
    

提交回复
热议问题