当前位置: 首页 > 知识库问答 >
问题:

使用Apache POI向特定单词添加注释或在docx文档中运行

奚卓
2023-03-14
        // Create comment
                        BigInteger cId = getCommentId(comments);
                        ctComment = comments.addNewComment();
                        ctComment.setAuthor("John Smith");
                        ctComment.setInitials("JS");
                        ctComment.setDate(new GregorianCalendar(Locale.getDefault()));
                        ctComment.addNewP().addNewR().addNewT().setStringValue("Test Comment");
                        ctComment.setId(cId);
                        
        // Set CommentRangeStart
                        String uri = CTMarkupRange.type.getName().getNamespaceURI();
                        String localPart = "commentRangeStart";

                        // XmlCursor cursor = p.getCTP().newCursor();
                        XmlCursor cursor = r.getCTR().newCursor();  
                        cursor.toFirstChild();
                        cursor.beginElement(localPart, uri);
                        cursor.toParent();
                        CTMarkupRange commentRangeStart =  (CTMarkupRange) cursor.getObject(); // This line throws a ClassCastException error
                        cursor.dispose();

                        commentRangeStart.setId(cId);

        // Set CommentRangeEnd and CommentReference

                        p.getCTP().addNewCommentRangeEnd().setId(cId);
                        // p.getCTP().addNewR().addNewCommentReference().setId(cId);
                        r.getCTR().addNewCommentReference().setId(cId);
for(XWPFParagraph p:paragraphs){
    List<XWPFRun> runs = p.getRuns();
    if (runs.size() > 0) {
        for (XWPFRun r : runs) {
            String text = r.getText(0);
            for (Map.Entry<String, List<String>> entry : rules.entrySet()) {
                String key = entry.getKey();
                List<String> value = entry.getValue();

                for (int i = 0; i < value.size(); i++) {
                    if (text != null && regexContains(text, value.get(i))) {
                        // Create comment
                        BigInteger cId = getCommentId(comments);
                        ctComment = comments.addNewComment();
                        ctComment.setAuthor("John Smith");
                        ctComment.setInitials("JS");
                        ctComment.setDate(new GregorianCalendar(Locale.getDefault()));
                        ctComment.addNewP().addNewR().addNewT().setStringValue(key);
                        ctComment.setId(cId);

                        // New snippet from Axel Richter
                        p.getCTP().addNewCommentRangeStart().setId(cId);
                        

                        p.getCTP().addNewCommentRangeEnd().setId(cId);
                        p.getCTP().addNewR().addNewCommentReference().setId(cId);
                    }
                }
            }
        }
    }

}

共有1个答案

谷梁翰飞
2023-03-14

这并不像你想象的那么难。

若要对段落内的运行进行注释,需要在段落中的文本运行开始之前设置注释范围start。在段落中文本运行结束后,需要设置注释范围结束。这正是我的代码示例已经完成的。当然,我的代码示例中的所有段落都只运行了一个文本。

在下面的完整示例中,第二个注释仅注释单词“second”。为此,该段有三个文本运行。第一个有文本“段落与”,第二个有文本“第二”并有注释,第三个有文本“注释”。

import java.io.*;

import org.apache.poi.*;
import org.apache.poi.ooxml.*;
import org.apache.poi.openxml4j.opc.*;
import org.apache.xmlbeans.*;

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

import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import javax.xml.namespace.QName;

import java.math.BigInteger;
import java.util.GregorianCalendar;
import java.util.Locale;


public class CreateWordWithComments {

//a method for creating the CommentsDocument /word/comments.xml in the *.docx ZIP archive  
 private static MyXWPFCommentsDocument createCommentsDocument(XWPFDocument document) throws Exception {
  OPCPackage oPCPackage = document.getPackage();
  PackagePartName partName = PackagingURIHelper.createPartName("/word/comments.xml");
  PackagePart part = oPCPackage.createPart(partName, "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml");
  MyXWPFCommentsDocument myXWPFCommentsDocument = new MyXWPFCommentsDocument(part);

  String rId = "rId" + (document.getRelationParts().size()+1);
  document.addRelation(rId, XWPFRelation.COMMENT, myXWPFCommentsDocument);

  return myXWPFCommentsDocument;
 }

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

  XWPFDocument document = new XWPFDocument();

  MyXWPFCommentsDocument myXWPFCommentsDocument = createCommentsDocument(document);

  CTComments comments = myXWPFCommentsDocument.getComments();
  CTComment ctComment;
  XWPFParagraph paragraph;
  XWPFRun run;

//first comment
  BigInteger cId = BigInteger.ZERO;

  ctComment = comments.addNewComment();
  ctComment.setAuthor("Axel Ríchter");
  ctComment.setInitials("AR");
  ctComment.setDate(new GregorianCalendar(Locale.US));
  ctComment.addNewP().addNewR().addNewT().setStringValue("The first comment.");
  ctComment.setId(cId);

  paragraph = document.createParagraph();

  paragraph.getCTP().addNewCommentRangeStart().setId(cId); //comment range start is set before text run
  run = paragraph.createRun();
  run.setText("Paragraph with the first comment.");
  paragraph.getCTP().addNewCommentRangeEnd().setId(cId); //comment range end is set after text run

  paragraph.getCTP().addNewR().addNewCommentReference().setId(cId); 

//paragraph without comment
  paragraph = document.createParagraph();
  run = paragraph.createRun();
  run.setText("Paragraph without comment.");

//second comment
  cId = cId.add(BigInteger.ONE);

  ctComment = comments.addNewComment();
  ctComment.setAuthor("Axel Ríchter");
  ctComment.setInitials("AR");
  ctComment.setDate(new GregorianCalendar(Locale.US));
  ctComment.addNewP().addNewR().addNewT().setStringValue("The second comment. Comments the word \"second\".");
  ctComment.setId(cId);

  paragraph = document.createParagraph();
  run = paragraph.createRun();
  run.setText("Paragraph with the ");

  paragraph.getCTP().addNewCommentRangeStart().setId(cId); //comment range start is set before text run
  run = paragraph.createRun();
  run.setText("second");
  paragraph.getCTP().addNewCommentRangeEnd().setId(cId); //comment range end is set after text run

  run = paragraph.createRun();
  run.setText(" comment.");

  paragraph.getCTP().addNewR().addNewCommentReference().setId(cId);

//write document
  FileOutputStream out = new FileOutputStream("CreateWordWithComments.docx");
  document.write(out);
  out.close();
  document.close();

 }

//a wrapper class for the CommentsDocument /word/comments.xml in the *.docx ZIP archive
 private static class MyXWPFCommentsDocument extends POIXMLDocumentPart {

  private CTComments comments;

  private MyXWPFCommentsDocument(PackagePart part) throws Exception {
   super(part);
   comments = CommentsDocument.Factory.newInstance().addNewComments();
  }

  private CTComments getComments() {
   return comments;
  }

  @Override
  protected void commit() throws IOException {
   XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
   xmlOptions.setSaveSyntheticDocumentElement(new QName(CTComments.type.getName().getNamespaceURI(), "comments"));
   PackagePart part = getPackagePart();
   OutputStream out = part.getOutputStream();
   comments.save(out, xmlOptions);
   out.close();
  }

 }

}
 类似资料:
  • 我无法使用ApachePOI删除docx文件中的所有注释。有没有其他方法可以使用docx4j api删除注释?

  • 我正在尝试创建一个包含多列的word文档。这样做(而不是使用表)的原因是,数据将跨越多个页面,在添加到新页面之前,我只能用列填充整个页面。 可以用ApachePOI实现吗?谢谢

  • 问题内容: 我使用Python-docx生成Microsoft Word文档。用户在编写以下内容时希望这样做:“大家早上好,这是我的%(profile_img)s,您喜欢吗?” 在一个HTML字段,我创建一个Word文档,我recuper用户的图片从数据库和i。由所述用户的图片替换键字%(profile_img)■ 不能在文件的结尾 。对于Python-docx,我们使用以下指令添加图片: 图片添

  • 我需要在表中的特定字段中添加两个不同的单词。 表是: 所以首先我需要选择我想要修改的记录: 假设结果是10条记录。 我现在有两个变量var1和var2 我现在需要将var1添加到表的field2的50%,将var2添加到其他50% 我该怎么做呢? 例子: 表: 第1条第2条 从mytable中选择*字段3=1 将返回2个字段。。。 下一个 将String1插入到50%的结果中,并将String2插

  • 我试图设置一些段落或文本在. docx文件使用Apache POI,我正在读取一个. docx文件作为模板从WEB-INF/资源/模板文件夹内我的战争文件,一旦读取,我想创建动态更多的表后,第9表用作模板,我可以添加更多的表格,但其他类型的内容(段落)被安排在文档的其他部分?有必要的形式来做这件事吗?

  • 问题内容: 通过使用文件中的以下代码块 我能够生成具有以下文件内容的文件 我想知道如何在生成的文件中添加评论?例如,生成的属性应具有以下内容: 我如何使用Ant来动态地做到这一点? 问题答案: 不支持编写带有多个注释的属性文件。为什么呢 PropertyFile.java ant属性文件任务由一个类支持,该类使用store()方法存储注释。从任务中仅提取一条注释,并将其传递给类以保存到文件中。 解