Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
412 views
in Technique[技术] by (71.8m points)

java - How to manipulate content of a comment with Apache POI

I would like to find a comment in Docx document (somehow, by author or ID...), then create new content. I was able to create a comment, with the help of this answer, but had no luck with manipulation.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As said in my answer linked in your question, until now the XWPFdocument will only read that package part while creating. There is neither write access nor a possibility to create that package part. This is mentioned in XWPFDocument.java - protected void onDocumentRead(): code line 210: "// TODO Create according XWPFComment class, extending POIXMLDocumentPart".

So we need doing this ourself until now. We need providing class extending POIXMLDocumentPart for comments and registering this relation instead of only relation to the simple POIXMLDocumentPart. So that and changings can be made which were committed while writing the XWPFDocument.

Example:

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 WordChangeComments {

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

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

  for (POIXMLDocumentPart.RelationPart rpart : document.getRelationParts()) {
   String relation = rpart.getRelationship().getRelationshipType();
   if (relation.equals(XWPFRelation.COMMENT.getRelation())) {
    POIXMLDocumentPart part = rpart.getDocumentPart(); //this is only POIXMLDocumentPart, not a high level class extending POIXMLDocumentPart
    //provide class extending POIXMLDocumentPart for comments 
    MyXWPFCommentsDocument myXWPFCommentsDocument = new MyXWPFCommentsDocument(part.getPackagePart());
    //and registering this relation instead of only relation to POIXMLDocumentPart
    String rId = document.getRelationId(part);
    document.addRelation(rId, XWPFRelation.COMMENT, myXWPFCommentsDocument);

    //now the comments are available from the new MyXWPFCommentsDocument 
    for (CTComment ctComment : myXWPFCommentsDocument.getComments().getCommentArray()) {

     System.out.print("Comment: Id: " + ctComment.getId());
     System.out.print(", Author: " + ctComment.getAuthor());
     System.out.print(", Date: " + ctComment.getDate());
     System.out.print(", Text: ");
     for (CTP ctp : ctComment.getPArray()) {
      System.out.print(ctp.newCursor().getTextValue());
     }
     System.out.println();

     //and changings can be made which were committed while writing the XWPFDocument
     if (BigInteger.ONE.equals(ctComment.getId())) { //the second comment (Id 0 = first)
      ctComment.setAuthor("New Author");
      ctComment.setInitials("NA");
      ctComment.setDate(new GregorianCalendar(Locale.US));
      CTP newCTP = CTP.Factory.newInstance();
      newCTP.addNewR().addNewT().setStringValue("The new Text for Comment with Id 1.");
      ctComment.setPArray(new CTP[]{newCTP });
     }
    }
   }
  }

  document.write(new FileOutputStream("WordDocumentHavingComments.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.parse(part.getInputStream(), DEFAULT_XML_OPTIONS).getComments();
  }

  private CTComments getComments() {
   return comments;
  }

  @Override
  protected void commit() throws IOException {

System.out.println("============MyXWPFCommentsDocument is committed=================");

   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();
  }

 }

}

This works for apache poi 3.17. Since apache poi 4.0.0 the ooxml part is separated. So there must be:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...