Page 1 of 1

content control and altChunk

PostPosted: Thu Aug 26, 2010 3:05 pm
by bzha005
Hi Guys,

I need help on how to use content control and altChunk together to insert a docx into another docx. I find a useful link talking about this using Open XML SDK. http://devmeat.com/show/172347. Basically it define a content control in template and at run time try to locate the content control and replace it with altChunk.

I tried to do the same thing using docx4j API, I managed to locate the content control, but can not delete it and insert an altChunk at the content control's place. Is there anyone know how to do this? The following is my code.

Code: Select all
private static void insertDocument(WordprocessingMLPackage wordMLPackage) throws Exception {
        MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
        String xpathSdt = "//w:sdt";
        List<Object> list = documentPart.getJAXBNodesViaXPath(xpathSdt, false);
       
        for(Iterator<Object> it = list.iterator(); it.hasNext();) {
            Object o = XmlUtils.unwrap(it.next());
            if (o instanceof SdtBlock ) {
                SdtBlock sdt = (SdtBlock)o;
                Tag tag = sdt.getSdtPr().getTag();                             
                String val = tag.getVal();
                if (val != null && val.startsWith("insertdoc=")) { // my content control has tag start with "insertdoc="
                    //find the name of the file to be inserted.
                    String fileName = val.substring(val.indexOf("=") + 1);

                    //insert altChunk. how to do this?
                   
                    //try to remove the content control, but after save, the content control still exists
                    it.remove(); 
                }
            }
        }
    }

Re: content control and altChunk

PostPosted: Thu Aug 26, 2010 3:47 pm
by jason
sdt.getParent() will give you the JAXB object of which your sdt is a child. (All objects have the getParent method)

Since it needs to be a paragraph (ie block) level object if you are to replace it with an altChunk, the parent is probably Body.

Then use Body's

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


to remove your sdt, and insert the altChunk.

When you have it working, it might be useful to others if you could post the result here. thanks.

Re: content control and altChunk

PostPosted: Fri Aug 27, 2010 9:03 am
by bzha005
Hi Jason,
I made it work. Following is my code, please have a quick review and see if I did wrong.


Code: Select all
  private static void insertDocument(WordprocessingMLPackage wordMLPackage) throws Exception {
        MainDocumentPart mainPart = wordMLPackage.getMainDocumentPart();
        String xpathSdt = "//w:body";
        Body body = (Body) mainPart.getJAXBNodesViaXPath(xpathSdt, false).get(0);
        List<Object> egBlockLevelElts = body.getEGBlockLevelElts();
        String fileName = null;
        int index = -1;
        for (int i = 0; i < egBlockLevelElts.size(); i++) {
            Object o = egBlockLevelElts.get(i);
            if (o instanceof SdtBlock) {
                SdtBlock sdt = (SdtBlock) o;
                Tag tag = sdt.getSdtPr().getTag();
                String val = tag.getVal();
                if (val != null && val.startsWith("insertdoc=")) {
                    fileName = val.substring(val.indexOf("=") + 1);
                    index = i;
                    break;
                }
            }
        }
        replaceContentControlWithAltChunk(mainPart, egBlockLevelElts, fileName, index);
    }

    private static void replaceContentControlWithAltChunk(MainDocumentPart mainPart, List<Object> egBlockLevelElts,
            String fileName, int index) throws Exception {

        egBlockLevelElts.remove(index);

        AlternativeFormatInputPart afiPart = new AlternativeFormatInputPart(new PartName("/chunk.docx"));
        afiPart.setBinaryData(new FileInputStream(System.getProperty("user.dir") + "/sample-docs/databinding/" +
                fileName));
        afiPart.setContentType(new ContentType(
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")); // docx
        Relationship altChunkRel = mainPart.addTargetPart(afiPart);
        CTAltChunk ac = Context.getWmlObjectFactory().createCTAltChunk();
        ac.setId(altChunkRel.getId());

        egBlockLevelElts.add(index, ac);
    }

Re: content control and altChunk

PostPosted: Fri Aug 27, 2010 9:37 am
by jason
A couple of thoughts:-

A possibility would be to extend the databinding conventions to cover not just conditional content controls and repeats, but also altChunk (ie your tag insertdoc=). In effect, what you have done would be somewhat standardised.

The problem with altChunk at present though is that the document has to be opened in Word in order to process the components. In other words, if you use altChunk, then try to create a PDF in docx4j, that content will be missing. It would be nice to write some code which can take a docx altChunk and change it into normal docx content.

Re: content control and altChunk

PostPosted: Fri Aug 27, 2010 10:10 am
by bzha005
Hi Jason,
That is great! I already realized the pdf conversion problem. Are you going to do this in recent release?

Re: content control and altChunk

PostPosted: Tue Aug 31, 2010 9:13 am
by jason
bzha005 wrote:I already realized the pdf conversion problem. Are you going to do this in recent release?


I don't have any plans to do so. But if you'd like it enough to make a financial contribution, I could add this functionality as a top priority. Let's discuss by email if you are interested.

Re: content control and altChunk

PostPosted: Sun Nov 14, 2010 8:17 pm
by jason
I've now created a paid extension for docx4j which can process a w:altChunk

See http://dev.plutext.org/blog/2010/11/mer ... documents/ for details.

You can buy it at www.plutext.com. Purchases of this extension support the further development of docx4j.

Re: content control and altChunk

PostPosted: Tue Nov 16, 2010 9:15 pm
by jason
jason wrote:A possibility would be to extend the databinding conventions to cover not just conditional content controls and repeats, but also altChunk (ie your tag insertdoc=).


I've udated the OpenDoPE conventions with an od:component element, which specifies a docx to be included, see http://dev.plutext.org/svn/docx4j/trunk ... tions.html

This is implemented in docx4j as of today, but unless you have the MergeDocx extension, just results in a w:altChunk being inserted (on which docx4j performs no further processing, so it ought not contain repeats,conditionals etc).

If you do have the MergeDocx extension, the altChunk is processed, with any repeats conditionals or components in it also being processed.