为了账号安全,请及时绑定邮箱和手机立即绑定

java处理word文档的问题

java处理word文档的问题

郎朗坤 2022-12-28 16:50:42
我需要在 java 中替换 Word 文档文件中的某些字段。我正在使用 Apache Poi 库,我正在使用此代码替换单词。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)  {                            System.out.println(text);                            if (text.contains("[Title]")) {                                text = text.replace("[Title]", wordBody.getTitle());//your content                                r.setText(text, 0);                            }if(text.contains("[Ref_no]")){                                text=text.replace("[Ref_no]",wordBody.getRefNumber());                                r.setText(text,0);                            }                            if(text.contains("[In_date]")){                                text=text.replace("[In_date]",wordBody.getDate());                                r.setText(text,0);                            }if(text.contains("[FirstName]")){                                text=text.replace("[FirstName]",wordBody.getFirstName());                                r.setText(text,0);                            }if(text.contains("[MiddleName]")){                                text=text.replace("[MiddleName]",wordBody.getMiddleName());                                r.setText(text,0);                            }                            }                        }                    }                }            }所以我提到并不是所有的单词都被替换了,我不知道如何修复它,然后我打印出了我得到的所有文本,我得到了类似的东西This is to certify that [Title] [FirstName] [MiddleName] [Surname] has purchased [Vehicle_Type] having registration [Reg_No] from our [Location] Showroom.Issued By,[Issuer所以我需要替换 [] 括号中的字段,其中一些作为 [Surname] 打印好的,但其中一些作为 [MIddleName] 正在更改行,我认为这是行不通的。这是我的文字
查看完整描述

2 回答

?
狐的传说

TA贡献1804条经验 获得超3个赞

如果您查看屏幕截图,您会在 MiddleName、Vehicle_Type 和 Reg_No 下看到红色波浪线。这意味着,它Word检测到这里可能存在拼写问题。这也存储在文件中,这就是为什么文本 [MIddleName]、[Vehicle_Type] 和 [Reg_No] 没有与它们周围的括号一起出现在一个文本行中。括号在他们自己的文本运行中,并且文本与可能的拼写问题一起标记。

这是一个众所周知的问题,一些图书馆已经尝试通过比仅在文本运行中搜索它们更复杂的方式检测文本变量来解决这个问题。例如有templ4docx

但我更喜欢的方式是另一种。Word长期以来提供使用文本表单字段。请参阅使用表单域。请注意,这里指的是遗留表单字段,而不是 ActiveX 表单字段。

有关示例,请参阅替换 .docx 中的文本模板(Apache POI、Docx4j 或其他)

您的案例的修改示例:

Word模板.docx:

//img1.sycdn.imooc.com//63ac0399000197e608510559.jpg

所有灰色字段都是从开发人员选项卡插入的遗留文本表单字段。它们Text Form Field Options的Bookmark:名称是Text1, Text2, ... 并且根据需要设置默认文本。


代码:


import java.io.FileOutputStream;

import java.io.FileInputStream;


import org.apache.poi.xwpf.usermodel.*;


import org.apache.xmlbeans.XmlObject;

import org.apache.xmlbeans.XmlCursor;

import org.apache.xmlbeans.SimpleValue;

import javax.xml.namespace.QName;


public class WordReplaceTextInFormFields {


 private static void replaceFormFieldText(XWPFDocument document, String ffname, String text) {

  boolean foundformfield = false;

  for (XWPFParagraph paragraph : document.getParagraphs()) {

   for (XWPFRun run : paragraph.getRuns()) {

    XmlCursor cursor = run.getCTR().newCursor();

    cursor.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:fldChar/@w:fldCharType");

    while(cursor.hasNextSelection()) {

     cursor.toNextSelection();

     XmlObject obj = cursor.getObject();

     if ("begin".equals(((SimpleValue)obj).getStringValue())) {

      cursor.toParent();

      obj = cursor.getObject();

      obj = obj.selectPath("declare namespace w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' .//w:ffData/w:name/@w:val")[0];

      if (ffname.equals(((SimpleValue)obj).getStringValue())) {

       foundformfield = true;

      } else {

       foundformfield = false;

      }

     } else if ("end".equals(((SimpleValue)obj).getStringValue())) {

      if (foundformfield) return;

      foundformfield = false;

     }

    }

    if (foundformfield && run.getCTR().getTList().size() > 0) {

     run.getCTR().getTList().get(0).setStringValue(text);

     foundformfield = false;

//System.out.println(run.getCTR());

    }

   }

  }

 }


 public static void main(String[] args) throws Exception {


  XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));


  replaceFormFieldText(document, "Text1", "Mrs.");

  replaceFormFieldText(document, "Text2", "Janis");

  replaceFormFieldText(document, "Text3", "Lyn");

  replaceFormFieldText(document, "Text4", "Joplin");

  replaceFormFieldText(document, "Text5", "Mercedes Benz");

  replaceFormFieldText(document, "Text6", "1234-56-789");

  replaceFormFieldText(document, "Text7", "Stuttgart");


  FileOutputStream out = new FileOutputStream("WordReplaceTextInFormFields.docx");

  document.write(out);

  out.close();

  document.close();

 }

}

此代码使用并需要FAQ-N10025中提到apache poi 4.1.0的所有模式的完整 jar 进行测试。ooxml-schemas-1.4.jar


结果:

//img1.sycdn.imooc.com//63ac03a80001829408420513.jpg

请注意,文本字段的灰色背景仅在GUI. 默认情况下不会打印出来。

优点:

表单域内容只能整体格式化。所以表单字段内容永远不会撕裂。

文档可以受到保护,因此只能填写表单字段。然后模板也可以用作表单Word GUI


查看完整回答
反对 回复 2022-12-28
?
忽然笑

TA贡献1806条经验 获得超5个赞

如果您正在寻找一种超级快速修复来防止将文本拆分为多个运行,以便它可以被 java 程序识别/读取,请执行以下操作:

  1. 在一次运行中复制您想要的文本

  2. 将其粘贴到记事本中(删除所有 docx 格式)

  3. 将该文本复制并粘贴到word文档中,点击保存。

现在它将作为一次运行插入。


查看完整回答
反对 回复 2022-12-28
  • 2 回答
  • 0 关注
  • 381 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号