Page 1 of 1

add a Comment footnote to docx

PostPosted: Tue Oct 05, 2010 7:23 am
by maechr
Hello!
Is it possible to add a comment, footnote to a docx file.
And when yes how?
Thanks

Re: add a Comment footnote to docx

PostPosted: Tue Oct 05, 2010 9:33 am
by jason
Do you mean a footnote, or a comment? (Word 2007 does not appear to allow a comment in a footer?)

For either the process is similar:

- create the footnote or comment part, and add it to the document

wordDocumentPart.addTargetPart(part);

- then you can add a footnote or comment, which means adding it to the footnote/comment part, and adding a footnote/comment reference to the document itself

I don't have example code handy right now, but hopefully this is enough to get you going. You should create a Word docx which contains what you are looking for, and examine its XML to see what you need to create.

Once you get it working, pls post it here as an example for others. Thanks.

Re: add a Comment footnote to docx

PostPosted: Wed Oct 13, 2010 7:37 am
by maechr
Thanks for the fast answer.
When I try to read the MainDocumentPart I get the following error
ava.lang.NoClassDefFoundError: org/apache/commons/vfs/FileSystemException

Code

mlPackage = new WordprocessingMLPackage().load(new java.io.File(
document.getAbsolutePath()));

I use the docx4j-nightly-20100914.jar
Thanks

Re: add a Comment footnote to docx

PostPosted: Wed Oct 13, 2010 8:10 am
by jason
You are missing the commons-vfs dependency.

See http://dev.plutext.org/docx4j/docx4j-2.5.0/

Re: add a Comment footnote to docx

PostPosted: Wed Oct 13, 2010 8:43 am
by maechr
Once more thanks!

From the template document I knew, that I have to add for a comment or a footnote a Relatonship in
\word\_rels\document.xml.rels
Is there a code example for adding a new Relationship to this file.
Thanks

Re: add a Comment footnote to docx

PostPosted: Wed Oct 13, 2010 12:20 pm
by jason
Code: Select all
wordMLPackage.getMainDocumentPart().addTargetPart(yourNewPart);


See http://dev.plutext.org/docx4j/javadoc-2 ... parts.Part, java.lang.String)

This is covered in the "Adding a Part" section of the Getting Started guide :-)

Re: add a Comment footnote to docx

PostPosted: Thu Oct 14, 2010 9:38 am
by maechr
Hello again!

I tryed to add the relationship with the example for hyperlinks
http://dev.plutext.org/trac/docx4j/browser/trunk/docx4j/src/main/java/org/docx4j/samples/HyperlinkTest.java
and changed id for comments
First I only want to add the relationship and test it. by storing the file I get NullPointer Exception.
My testDocument is a new Document with no content. I only opend a new document and saved.

Error

org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:364)
at org.docx4j.openpackaging.io.SaveToZipFile.save(SaveToZipFile.java:158)
at org.docx4j.openpackaging.io.SaveToZipFile.save(SaveToZipFile.java:99)
at org.docx4j.openpackaging.packages.WordprocessingMLPackage.save(WordprocessingMLPackage.java:202)
at at.jku.dqm.annotation.TestComment.main(TestComment.java:38)
Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:364)
at org.docx4j.openpackaging.io.SaveToZipFile.savePart(SaveToZipFile.java:411)
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:359)
... 4 more
Caused by: java.lang.NullPointerException
at org.docx4j.openpackaging.io.SaveToZipFile.savePart(SaveToZipFile.java:383)
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:359)
... 6 more
org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:364)
at org.docx4j.openpackaging.io.SaveToZipFile.save(SaveToZipFile.java:158)
at org.docx4j.openpackaging.io.SaveToZipFile.save(SaveToZipFile.java:99)
at org.docx4j.openpackaging.packages.WordprocessingMLPackage.save(WordprocessingMLPackage.java:202)
at at.jku.dqm.annotation.TestComment.main(TestComment.java:38)
Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:364)
at org.docx4j.openpackaging.io.SaveToZipFile.savePart(SaveToZipFile.java:411)
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:359)
... 4 more
Caused by: java.lang.NullPointerException
at org.docx4j.openpackaging.io.SaveToZipFile.savePart(SaveToZipFile.java:383)
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:359)
... 6 more


Code:

mlPackage = new WordprocessingMLPackage().load(new java.io.File(
document.getAbsolutePath()));

org.docx4j.relationships.ObjectFactory factory = new org.docx4j.relationships.ObjectFactory();
org.docx4j.relationships.Relationship rel = factory
.createRelationship();
rel.setType(Namespaces.COMMENTS);
rel.setId(mlPackage.getMainDocumentPart().getRelationshipsPart().getNextId());
rel.setTarget("comments.xml");
mlPackage.getMainDocumentPart().getRelationshipsPart()
.addRelationship(rel);

mlPackage.save(new java.io.File(System.getProperty("user.dir")
+ "/out-hyperlink.docx"));

Thanks again!

Re: add a Comment footnote to docx

PostPosted: Thu Oct 14, 2010 6:46 pm
by jason
With logging turned on, you can see the problem is that your comments part doesn't exist:

Code: Select all
14.10.2010 18:14:34 *INFO * SaveToZipFile: PUT SUCCESS: word/_rels/document.xml.rels (SaveToZipFile.java, line 204)
14.10.2010 18:14:34 *INFO * SaveToZipFile: For Relationship Id=rId1 Source is /word/document.xml, Target is comments.xml (SaveToZipFile.java, line 311)
14.10.2010 18:14:34 *INFO * SaveToZipFile: Getting part /word/comments.xml (SaveToZipFile.java, line 349)
14.10.2010 18:14:34 *DEBUG* PartName: Trying to create part name /word/comments.xml (PartName.java, line 150)
14.10.2010 18:14:34 *DEBUG* PartName: /word/comments.xml part name created. (PartName.java, line 170)
14.10.2010 18:14:34 *ERROR* SaveToZipFile: Part word/comments.xml not found! (SaveToZipFile.java, line 354)


SaveToZipFile walks the tree of relationships to zip all the parts up, so a missing part causes a problem. (You created the rel, but not the part it points to)

Here is a full example of adding the comments part to a new docx:
Code: Select all
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.CommentsPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Comments;

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

      // Create a package
      WordprocessingMLPackage wmlPack = new WordprocessingMLPackage();

      // Create main document part
      MainDocumentPart wordDocumentPart = new MainDocumentPart();      
      
      // Create main document part content
      org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory();
      org.docx4j.wml.Body  body = factory.createBody();      
      org.docx4j.wml.Document wmlDocumentEl = factory.createDocument();
      
      wmlDocumentEl.setBody(body);
      wordDocumentPart.setJaxbElement(wmlDocumentEl);
      wmlPack.addTargetPart(wordDocumentPart);
      
      CommentsPart cp = new CommentsPart();
      // Part must have minimal contents
      Comments comments = factory.createComments();
      cp.setJaxbElement(comments);
      
      wordDocumentPart.addTargetPart(cp);
      
      // Now you can add comments to your comments part,
      // and comment refs in your main document part   
            
      wmlPack.save(new java.io.File(System.getProperty("user.dir")+ "/out-m.docx"));       
    }
}



Comment refs in the main document part look like:

Code: Select all
          <w:p>
            <w:commentRangeStart w:id="0"/>
            <w:r>
              <w:t>hello</w:t>
            </w:r>
            <w:commentRangeEnd w:id="0"/>
            <w:r>
              <w:rPr>
                <w:rStyle w:val="CommentReference"/>
              </w:rPr>
              <w:commentReference w:id="0"/>
            </w:r>
          </w:p>


Note that they don't use the rel id; they point straight to a w:comment/@w:id in the comments part.

So they're different from images and hyperlinks, and more similar to footnotes and endnotes.

Re: add a Comment footnote to docx

PostPosted: Sat Oct 16, 2010 9:54 am
by maechr
First for all a code for checking the relationship and add a comment rel to /word/_rels/document.xml.rels if necessary.
Code: Select all
import java.util.Iterator;
import java.util.List;

import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.JaxbXmlPart;
import org.docx4j.openpackaging.parts.WordprocessingML.CommentsPart;
import org.docx4j.relationships.Relationship;
import org.docx4j.relationships.Relationships;
import org.docx4j.wml.ObjectFactory;

import util.RelationshipName;

public class Comment {

    private WordprocessingMLPackage wordMlPackage;
    private boolean relSet = false;

    public Comment(WordprocessingMLPackage wordMLPack) {
        this.wordMlPackage = wordMLPack;
        setCommentRel();
    }

    private void setCommentRel() {
        if (!commentRelSet()) {
            CommentsPart cp;
            try {
                cp = new CommentsPart();
                // Part must have minimal contents
                org.docx4j.wml.ObjectFactory wmlObjectFactory = new ObjectFactory();
                wordMlPackage.getMainDocumentPart().addTargetPart(cp);
            } catch (InvalidFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    private boolean commentRelSet() {
        Relationship relShip;
        boolean relSet = false;
        if (!relSet) {
            JaxbXmlPart<Relationships> jxpRelShips = wordMlPackage
                    .getMainDocumentPart().getOwningRelationshipPart();
            Relationships pk = jxpRelShips.getJaxbElement();

            List<Relationship> mc = pk.getRelationship();

            Iterator<Relationship> it = mc.iterator();
            while (it.hasNext() && !relSet) {
                relShip = it.next();
                if (relShip.getValue().equalsIgnoreCase(
                        RelationshipName.commentIdentifier)) {
                    relSet = true;
                }
            }
        }
        return relSet;
    }
}


next on my list insert a comment to document xml on a spezific position

Re: add a Comment footnote to docx

PostPosted: Sun Oct 17, 2010 9:29 am
by maechr
Where or better how do I find the comment.xml file :?: . So that I can read out all comments or add a new one.
Thanks

Re: add a Comment footnote to docx

PostPosted: Sun Oct 17, 2010 3:12 pm
by jason
My code earlier in the thread included:
Code: Select all
     CommentsPart cp = new CommentsPart();
      // Part must have minimal contents
      Comments comments = factory.createComments();
      cp.setJaxbElement(comments);
     
      wordDocumentPart.addTargetPart(cp)


The comments part cp is the comment.xml file.

The Comments object comments will contain your comments.

If you are looking for an existing comments part in an existing document, you can just do getMainDocumentPart().getCommentsPart()

(This is probably an easier approach than the code in your previous post, which appears to be looking in the pacakge relationships with getOwningRelationshipPart(), rather than the MDP's rels)

Re: add a Comment footnote to docx

PostPosted: Mon Oct 18, 2010 8:51 am
by maechr
Thanks for the help again :D :D .
I was asking because I am not able to add a comment to the commentsPart.
Code: Select all
<w:comment w:id="1" w:author="autor" w:date="2010-08-26T10:03:00Z" w:initials="AM">
      <w:p>
         <w:pPr>
            <w:pStyle w:val="Kommentartext"/>
            <w:rPr>
               <w:lang w:val="de-AT"/>
            </w:rPr>
         </w:pPr>
         <w:r>
            <w:rPr>
               <w:rStyle w:val="Kommentarzeichen"/>
            </w:rPr>
            <w:annotationRef/>
         </w:r>
         <w:r w:rsidR="00AC177F">
            <w:rPr>
               <w:lang w:val="de-AT"/>
            </w:rPr>
            <w:t>dfsadfas</w:t>
         </w:r>
      </w:p>
   </w:comment>

I knew how the comment should look in the comment.xml but what methode and Object I have to use for adding a comment.
Thanks

Re: add a Comment footnote to docx

PostPosted: Mon Oct 18, 2010 10:25 am
by jason
There are 2 basic ways to create your XML using JAXB:

The classic JAXB way is to use the ObjectFactory's .createX methods. For example:

Code: Select all
      Comment c = Context.getWmlObjectFactory().createCommentsComment()

The challenge with this is to know what object it is you are trying to create. To find this out, run something like OpenMainDocumentAndTraverse on your comments part. To do that, just replace the body variable like so:

Code: Select all
      Comments body = documentPart.getCommentsPart().getJaxbElement();


This tells you:

Code: Select all
*DEBUG* TraversalUtil: getting children of org.docx4j.wml.Comments (TraversalUtil.java, line 110)
    org.docx4j.wml.Comments$Comment  ""


If you look at Comments.Comment, you'll see it is similar to document.xml's body, with

Code: Select all
        public List<Object> getEGBlockLevelElts()


Another way is to just unmarshal the XML (eg a String representing a comment to be inserted into the document).

Code: Select all
    // Assuming String xml contains the XML above
    org.docx4j.wml.Comments.Comment comment = XmlUtils.unmarshalString(xml);


unmarshalString might result in a problem relating to missing @XmlRootElement annontation (see the Getting started guide). If you need to be explicit about the type, you can use:

Code: Select all
  public static Object unmarshalString(String str, JAXBContext jc, Class declaredType)


If you are taking this second approach, don't forget to add the w: namespace declaration into your string!

Re: add a Comment footnote to docx

PostPosted: Tue Oct 19, 2010 8:29 am
by maechr
I already got the comment.

But my main problems are

setting the text

and

add the comment to the comment.xml.

I tried it with a
Code: Select all
org.docx4j.wml.ObjectFactory
and created a comment and add it to the commentspart.
but also i tried your approach with the
Code: Select all
Context.getWmlObjectFactory().createCommentsComment()


But with the context comment i dont knew what to do.

After saving the file.
The comments.xml is by the wmlObjectFactory + commentsPart.add(xxxxx) empty.

Thanks again

Re: add a Comment footnote to docx

PostPosted: Tue Oct 19, 2010 8:41 am
by jason
Are you doing getEGBlockLevelElts().add(comment)?

You'll need to post your code if I'm to tell you what you are doing wrong.

Re: add a Comment footnote to docx

PostPosted: Tue Oct 19, 2010 7:56 pm
by maechr
Hello Jason!

I tried it with that code
Code: Select all
wordMlPackage.getMainDocumentPart().getJaxbElement().getBody().getEGBlockLevelElts().add(comment);


But by getJaxbElement() i get a nullpointer exception.

thanks

Re: add a Comment footnote to docx

PostPosted: Tue Oct 19, 2010 10:38 pm
by jason
In your addNewComment method, you are adding the comment to itself:

Code: Select all
      c.getEGBlockLevelElts().add(c);


You should be adding it to your Comments object (which you've called "comment"):

Code: Select all
      comment.getEGBlockLevelElts().add(c);


You have a CommentsPart, but nowhere do you set its contents. For my earlier post:

Code: Select all
      CommentsPart cp = new CommentsPart();
      // Part must have minimal contents
      Comments comments = factory.createComments();
      cp.setJaxbElement(comments);


So, the result:

Code: Select all

public class CommentRel {
   
   private WordprocessingMLPackage wordMlPackage;
   private MainDocumentPart mainPart;
   private boolean relSet = false;
   private org.docx4j.wml.ObjectFactory wmlObjectFactory;
   private CommentsPart cmPart;

   
   public CommentRel(WordprocessingMLPackage wordMLPack) {
      this.wordMlPackage = wordMLPack;
      wmlObjectFactory = new ObjectFactory();
      setCommentRel();
      cmPart = wordMlPackage.getMainDocumentPart().getCommentsPart();
      mainPart = wordMLPack.getMainDocumentPart();
   }

   private void setCommentRel() {
      if (!commentRelSet()) {
         CommentsPart cp;
         try {
            cp = new CommentsPart();
            // Part must have minimal contents
            Comments comments = wmlObjectFactory.createComments();
               cp.setJaxbElement(comments);            
            
            wordMlPackage.getMainDocumentPart().addTargetPart(cp);
         } catch (InvalidFormatException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
   }

   private boolean commentRelSet() {
      return !(wordMlPackage.getMainDocumentPart().getCommentsPart() == null);
   }

   public void addNewComment(String author, String text) {
      
//      XMLGregorianCalendar xmlCal = new XMLGregorianCalendarImpl();  // You'll need to fix this!
      
//      CommentRangeEnd cRangeEnde = wmlObjectFactory.createCommentRangeEnd();
//      CommentRangeStart cRangeStart = wmlObjectFactory
//            .createCommentRangeStart();
      Comments comment = wmlObjectFactory.createComments();
//      Comments.Comment myCom = wm

      Comment c = Context.getWmlObjectFactory().createCommentsComment();
      System.out.println("test");
//      comment.setParent(cmPart);
      c.setAuthor(author);
//      c.setDate(xmlCal);
      cmPart.getJaxbElement().getComment().add(c);

      System.out.println("test ende");
   }

//   WordprocessingMLPackage wordML;

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

      final String APP_ROOT = "C:\\tmpxml\\CommentTest\\";
//      File document = new File(APP_ROOT + "Comment.docx");
      File document = new File(APP_ROOT + "Leer3.docx");

      WordprocessingMLPackage mlPackage;
      MainDocumentPart mDocPart;
      try {
         mlPackage = new WordprocessingMLPackage().load(new java.io.File(
               document.getCanonicalPath()));

         mDocPart = mlPackage.getMainDocumentPart();

         CommentRel myComment = new CommentRel(mlPackage);

         myComment.addNewComment("MC","Text");
//         my

//         FootnoteRel fnote1 = new FootnoteRel(mlPackage);
//
//         fnote1.setFootnote("autor","test");
          mlPackage.save(new File(APP_ROOT + "Leer3-OUT.docx"));
      } catch (Docx4JException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

   }
}



That is enough to set up a shell comment in your comments part. Notice I commented out your XMLGregorianCalendar xmlCal. So the comment doesn't have a date, yet.

You still need to add a reference to it to your document.xml

I guess I should add an addComment sample :-)

Notice I changed the output file, so you aren't writing over your input file. You won't get repeatable behaviour if you are doing that.