2016-12-14 11 views
1

Попытка заменить текст несколькими словами, разбросанными по разным прогонам в абзаце, используя образец, предоставленный @Thierry Bodhuin ниже, однако, он бросает под исключение:Замена текста несколькими словами в Apache POI XWPF не работает - org.apache.xmlbeans.impl.values.XmlValueDisconnectedException

Exception in thread "main" org.apache.xmlbeans.impl.values.XmlValueDisconnectedException 
at org.apache.xmlbeans.impl.values.XmlObjectBase.check_orphaned(XmlObjectBase.java:1258) 
at org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRImpl.isSetRsidDel(Unknown Source) 
at org.apache.poi.xwpf.usermodel.XWPFParagraph.getText(XWPFParagraph.java:221) 
at com.db.a.WordExtractReplaceFormat.replace(WordExtractReplaceFormat.java:60) 
at com.db.a.WordExtractReplaceFormat.replace(WordExtractReplaceFormat.java:52) 
at com.db.a.WordExtractReplaceFormat.replace(WordExtractReplaceFormat.java:37) 
at com.db.a.WordExtractReplaceFormat.main(WordExtractReplaceFormat.java:114) 

* фрагмент кода из этого ответа [Replacing a text in Apache POI XWPF на ** Thierry Bodhuin

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.TreeMap; 

import org.apache.poi.xwpf.usermodel.XWPFDocument; 
import org.apache.poi.xwpf.usermodel.XWPFParagraph; 
import org.apache.poi.xwpf.usermodel.XWPFRun; 

public class WordExtractReplaceFormat { 

private static Map<Integer, XWPFRun> getPosToRuns(XWPFParagraph paragraph) { 
    int pos = 0; 
    Map<Integer, XWPFRun> map = new HashMap<Integer, XWPFRun>(10); 
    for (XWPFRun run : paragraph.getRuns()) { 
     String runText = run.text(); 
     if (runText != null) { 
      for (int i = 0; i < runText.length(); i++) { 
       map.put(pos + i, run); 
      } 
      pos += runText.length(); 
     } 
    } 
    return (map); 
} 

public static <V> void replace(XWPFDocument document, Map<String, V> map) throws FileNotFoundException, IOException { 
    List<XWPFParagraph> paragraphs = document.getParagraphs(); 
    for (XWPFParagraph paragraph : paragraphs) { 
     replace(paragraph, map); 
    } 
    String filePath = "C:\\test-1.docx"; 
    saveWord(filePath, document); 
} 

public static <V> void replace(XWPFDocument document, String searchText, V replacement) { 
    List<XWPFParagraph> paragraphs = document.getParagraphs(); 
    for (XWPFParagraph paragraph : paragraphs) { 
     replace(paragraph, searchText, replacement); 
    } 
} 

private static <V> void replace(XWPFParagraph paragraph, Map<String, V> map) { 
    for (Map.Entry<String, V> entry : map.entrySet()) { 
     replace(paragraph, entry.getKey(), entry.getValue()); 
    } 
} 

public static <V> void replace(XWPFParagraph paragraph, String searchText, V replacement) { 
    boolean found = true; 
    while (found) { 
     found = false; 
     int pos = paragraph.getText().indexOf(searchText); 
     if (pos >= 0) { 
      found = true; 
      Map<Integer, XWPFRun> posToRuns = getPosToRuns(paragraph); 
      XWPFRun run = posToRuns.get(pos); 
      XWPFRun lastRun = posToRuns.get(pos + searchText.length() - 1); 
      int runNum = paragraph.getRuns().indexOf(run); 
      int lastRunNum = paragraph.getRuns().indexOf(lastRun); 
      String texts[] = replacement.toString().split("\n"); 
      run.setText(texts[0], 0); 
      XWPFRun newRun = run; 
      for (int i = 1; i < texts.length; i++) { 
       newRun.addCarriageReturn(); 
       newRun = paragraph.insertNewRun(runNum + i); 
       /* 
        We should copy all style attributes 
        to the newRun from run 
        also from background color, ... 
        Here we duplicate only the simple attributes... 
       */ 
       newRun.setText(texts[i]); 
       newRun.setBold(run.isBold()); 
       newRun.setCapitalized(run.isCapitalized()); 
       // newRun.setCharacterSpacing(run.getCharacterSpacing()); 
       newRun.setColor(run.getColor()); 
       newRun.setDoubleStrikethrough(run.isDoubleStrikeThrough()); 
       newRun.setEmbossed(run.isEmbossed()); 
       newRun.setFontFamily(run.getFontFamily()); 
       newRun.setFontSize(run.getFontSize()); 
       newRun.setImprinted(run.isImprinted()); 
       newRun.setItalic(run.isItalic()); 
       newRun.setKerning(run.getKerning()); 
       newRun.setShadow(run.isShadowed()); 
       newRun.setSmallCaps(run.isSmallCaps()); 
       newRun.setStrikeThrough(run.isStrikeThrough()); 
       newRun.setSubscript(run.getSubscript()); 
       newRun.setUnderline(run.getUnderline()); 
      } 
      for (int i = lastRunNum + texts.length - 1; i > runNum + texts.length - 1; i--) { 
       paragraph.removeRun(i); 
      } 
     } 
    } 
} 

public static void main(String[] args) throws FileNotFoundException, IOException { 
    XWPFDocument docx; 
    Map<String, String> keyValue = new TreeMap<>(); 
    keyValue.put("$<[Member] [Manager] [Officer]>", "Member Only"); 
    keyValue.put("${Lawyer_Name}", "Lawyer Name Updated with Actual"); 
    keyValue.put("${Place_Holder_Key}", "Place_Holder_value"); 

    WordExtractReplaceFormat wexrf = new WordExtractReplaceFormat(); 
    docx = new XWPFDocument(new FileInputStream("C:\\test.docx")); 
    wexrf.replace(docx, keyValue); 
} 

private static void saveWord(String filePath, XWPFDocument doc) throws FileNotFoundException, IOException{ 
    FileOutputStream out = null; 
    try{ 
     out = new FileOutputStream(filePath); 
     doc.write(out); 
    } 
    finally{ 
     out.close(); 
    } 
} 

}

** Код сбой в этой строке - int pos = paragraph.getText(). IndexOf (searchText);

+0

Вы пытаетесь найти и заменить одно слово с предложением (группа слов) или то, что, пожалуйста, объясните, что именно хочешь заменить .И это это одно слово или одно место? –

+0

Если вы просто пытаетесь найти слово и заменить другим (слово или слова) в docx, есть простой подход. –

+1

Требование состоит в том, чтобы найти группу слов (текст) из шаблона и удалить/заменить набор слов и сохранить только соответствующие слова, относящиеся к документу. Пример: searchText = "$ <[Member] [Manager] [Officer]>" replaceText = "Member alone". Примечание. SearchText может содержать более одного места в шаблоне. – RSB

ответ

0

Я только что попробовал приведенный ниже код и не уверен в вашем точном содержании docx. Но, как я наблюдаю, это прекрасно работает. !!!

Я предполагаю, что $ < [Member] [Manager] [Officer]> находится в вашем файле docx. это заменяет все содержимое даже заменяет каждый элемент, как менеджер и т.д.

public class Find_Replace_DOCX { 

     public static void main(String args[]) throws IOException, 
       InvalidFormatException, 
       org.apache.poi.openxml4j.exceptions.InvalidFormatException { 
      try { 

       /** 
       * if uploaded doc then use HWPF else if uploaded Docx file use 
       * XWPFDocument 
       */ 
       XWPFDocument doc = new XWPFDocument(
         OPCPackage.open("d:\\1\\11.docx")); 
       for (XWPFParagraph p : doc.getParagraphs()) { 
        List<XWPFRun> runs = p.getRuns(); 
        if (runs != null) { 
         for (XWPFRun r : runs) { 
          String text = r.getText(0); 
          if (text != null 
            && text.contains("$<[Member] [Manager] [Officer]>")) { 
           text = text.replace("Member", "new Member"); 
           text = text.replace("Manager", "new manager"); 
           text = text.replace("Officer", "new officer"); 
           // text = 
           // text.replace("$<[Member] [Manager] [Officer]>", 
           // "new content"); 
           r.setText(text, 0); 
          } 
         } 
        } 
       } 

       for (XWPFTable tbl : doc.getTables()) { 
        for (XWPFTableRow row : tbl.getRows()) { 
         for (XWPFTableCell cell : row.getTableCells()) { 
          for (XWPFParagraph p : cell.getParagraphs()) { 
           for (XWPFRun r : p.getRuns()) { 
            String text = r.getText(0); 
            if (text != null 
              && text.contains("$<[Member] [Manager] [Officer]>")) { 
             text = text.replace("Member", "new Member"); 
             text = text.replace("Manager", 
               "new manager"); 
             text = text.replace("Officer", 
               "new officer"); 
             // text = 
             // text.replace("$<[Member] [Manager] [Officer]>", 
             // "new content"); 
             r.setText(text, 0); 
            } 
           } 
          } 
         } 
        } 
       } 

       doc.write(new FileOutputStream("d:\\1\\output.docx")); 
      } finally { 

      } 

     } 

    } 
+0

import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; импорт org.apache.poi.xwpf.usermodel.XWPFTable; импорт org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; –

+0

Ваш код работает только в том случае, если searchText находится за один проход, однако в моем документе слова разбиваются на ** несколько запусков *, как указано в этом вопросе. Для нескольких запусков @ThierryBodhuin предоставляет фрагмент кода, как упоминалось в моем вопросе, но он вызывает исключение. Не уверен, как это можно сообщить Тьерри – RSB