如何通过Apache POI添加注释

4

我正在尝试通过apache poi api向MS Word文档添加评论。
我已经使用以下方法完成了部分工作:

CTMarkupRange commentStart = paragraph.getCTP().addNewCommentRangeStart();
commentStart.setId(BigInteger.ZERO);
XWPFRun run = paragraph.createRun();
run.setText("text");

CTMarkupRange commentEnd = paragraph.getCTP().addNewCommentRangeEnd();
commentEnd.setId(BigInteger.ZERO);

CTR ctr = paragraph.getCTP().addNewR();
CTMarkup ctMarkup = ctr.addNewCommentReference();
ctMarkup.setId(BigInteger.ZERO);

但我不知道如何将它链接到真正的评论,而且在API文档中也没有找到相关内容。
有人知道如何解决吗?

1个回答

6
在Office OpenXML Word文档(XWPF)中,评论位于*.docx ZIP存档文件的特殊CommentsDocument /word/comments.xml中。因此,我们首先需要访问此文档。但是直到现在,XWPFdocument仅在创建时读取该包部分。既不存在写入访问权限,也没有创建包部分的可能性。
因此,我们必须首先提供创建/word/comments.xml包部分并获得写入访问权限的可能性。
在下面的示例中,方法MyXWPFCommentsDocument createCommentsDocument(XWPFDocument document)创建包部分/word/comments.xml及其关系。类MyXWPFCommentsDocument是该包部分的包装器类,具有对其的写入访问权限。
import java.io.*;

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

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

import static org.apache.poi.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 = document.addRelation(null, XWPFRelation.COMMENT, myXWPFCommentsDocument).getRelationship().getId();

  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 Richter");
  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);

  run = paragraph.createRun();
  run.setText("Paragraph with the first comment.");

  paragraph.getCTP().addNewCommentRangeEnd().setId(cId);

  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 Richter");
  ctComment.setInitials("AR");
  ctComment.setDate(new GregorianCalendar(Locale.US));
  ctComment.addNewP().addNewR().addNewT().setStringValue("The second comment.");
  ctComment.setId(cId);

  paragraph = document.createParagraph();
  paragraph.getCTP().addNewCommentRangeStart().setId(cId);

  run = paragraph.createRun();
  run.setText("Paragraph with the second comment.");

  paragraph.getCTP().addNewCommentRangeEnd().setId(cId);

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

//write document
  document.write(new FileOutputStream("CreateWordWithComments.docx"));
  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();
  }

 }
}

这适用于 apache poi 3.17。自从 apache poi 4.0.0ooxml 部分分离出来了。所以必须有:

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

它完美地运行,并且根据解决方案,*.docx ZIP归档的其他部分(commentsExtended.xml)可以以同样的方式创建。非常感谢您的回答。 - Yuanan Zhang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接