Page 1 of 1

Copy Header from a docx file to use in other while creation

PostPosted: Mon Aug 29, 2016 8:29 pm
by saurabh
In my application user can upload a docx file for various purposes . And now we want to copy that header/footer part and use the same header while exporting to new docx file .
I search in docx4j forum but didnt find any clear was of doing this .Can someone pls help in this regard .
Thanks in advance !

Re: Copy Header from a docx file to use in other while creat

PostPosted: Tue Aug 30, 2016 10:04 pm
by sophie
Hi,

Searching for the same solution .
Is it possible to create header object from one existing word file(.docx) and use that header object part into another .docx file .

Re: Copy Header from a docx file to use in other while creat

PostPosted: Thu Sep 01, 2016 4:50 pm
by saurabh
Below is the code i am trying ....pls help whats wrong in this as m getting exception
1 Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: part store has changed, and sourcePartStore not set
2 Exception in thread "main" org.docx4j.openpackaging.exceptions.Docx4JException: Failed to add parts from relationships of /
3 Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: Problem saving part /word/header1.xml



private static ObjectFactory objectFactory = new ObjectFactory();

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

WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
.createPackage();

MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart();

Relationship relationship = createHeaderPart(wordMLPackage);

createHeaderReference(wordMLPackage, relationship);

wordMLPackage.save(new File("C:\\Users\\saurabh\\Desktop\\",
"headerFooter.docx"));
// mainDocumentPart.marshal(new FileOutputStream(new File(System
// .getProperty("user.dir"), "headerfooter.xml")));

System.out.println("done");
}

public static Relationship createHeaderPart(WordprocessingMLPackage wordprocessingMLPackage)
throws Exception {


WordprocessingMLPackage source = WordprocessingMLPackage.load(new File("C:\\Users\\saurabh\\Desktop\\My_Requirement.docx"));
RelationshipsPart rp = source.getMainDocumentPart().getRelationshipsPart();
Relationship rel = rp.getRelationshipByType(Namespaces.HEADER);

Part headerPart= rp.getPart(rel);
//headerPart.setPackage(wordprocessingMLPackage);
System.out.println("---------- "+headerPart.getPartName().getName());
headerPart.setPartName(new PartName("/word/header.xml"));


return wordprocessingMLPackage.getMainDocumentPart()
.addTargetPart(headerPart);

}

public static void createHeaderReference(
WordprocessingMLPackage wordprocessingMLPackage,
Relationship relationship )
throws InvalidFormatException {

List<SectionWrapper> sections = wordprocessingMLPackage.getDocumentModel().getSections();

SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
// There is always a section wrapper, but it might not contain a sectPr
if (sectPr==null ) {
sectPr = objectFactory.createSectPr();
wordprocessingMLPackage.getMainDocumentPart().addObject(sectPr);
sections.get(sections.size() - 1).setSectPr(sectPr);
}

HeaderReference headerReference = objectFactory.createHeaderReference();
headerReference.setId(relationship.getId());
headerReference.setType(HdrFtrRef.DEFAULT);
sectPr.getEGHdrFtrReferences().add(headerReference);// add header or
// footer references

}
}

Re: Copy Header from a docx file to use in other while creat

PostPosted: Fri Sep 02, 2016 9:39 pm
by saurabh
Hi Jason..
this requirement feasible or not with docx4j ???

Re: Copy Header from a docx file to use in other while creat

PostPosted: Sat Sep 03, 2016 8:38 am
by jason
saurabh wrote:Hi Jason..
this requirement feasible or not with docx4j ???


Sure, it is straightforward enough, and you were nearly there...

Sorry not to reply sooner, but when I'm busy, I have to prioritize questions/issues based on their significance to the project as a whole.

See modified/working code below, especially the comment I've added which explains the issue you encountered. In summary, when copying a part from an existing docx, you should instead clone its contents.

Rather than extracting a header from an existing docx, it might be better if you just read the XML from a header.xml file stored somewhere?

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
import java.io.File;
import java.util.List;

import org.docx4j.XmlUtils;
import org.docx4j.model.structure.SectionWrapper;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.relationships.Namespaces;
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart.AddPartBehaviour;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.HdrFtrRef;
import org.docx4j.wml.HeaderReference;
import org.docx4j.wml.ObjectFactory;
import org.docx4j.wml.SectPr;


public class headerfoo {

        private static ObjectFactory objectFactory = new ObjectFactory();

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

                WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
                                .createPackage();

                MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart();

                Relationship relationship = createHeaderPart(wordMLPackage);

                createHeaderReference(wordMLPackage, relationship);

                wordMLPackage.save(new File(
//                              "C:\\Users\\saurabh\\Desktop\\",
                                "headerFooter.docx"));

                System.out.println("done");
        }

        public static Relationship createHeaderPart(
                        WordprocessingMLPackage wordprocessingMLPackage) throws Exception {

                WordprocessingMLPackage source = WordprocessingMLPackage.load(new File(
//                              "C:\\Users\\saurabh\\Desktop\\" +
                                 "My_Requirement.docx"));
                RelationshipsPart rp = source.getMainDocumentPart()
                                .getRelationshipsPart();
                Relationship rel = rp.getRelationshipByType(Namespaces.HEADER);

                HeaderPart headerPart = (HeaderPart)rp.getPart(rel);
                // headerPart.setPackage(wordprocessingMLPackage);
                System.out.println("---------- " + headerPart.getPartName().getName());

                /* Caused by: org.docx4j.openpackaging.exceptions.Docx4JException: part store has changed, and sourcePartStore not set
                        at org.docx4j.openpackaging.io3.stores.ZipPartStore.saveJaxbXmlPart(ZipPartStore.java:242)
                       
                        For processing efficiency, docx4j doesn't actually fully load a part until it is needed.
                       
                        To load it, it needs to know where to find it (ie its SourcePartStore).
                       
                        This info is stored at the package level, so if you move the part to a new package, that info is lost.
                       
                        3 ways to work around this:
                       
                        1. wordprocessingMLPackage.setSourcePartStore(headerPart.getPackage().getSourcePartStore());
                       
                                but not so good, since in the general case, you might want to use several source packages,
                                and, in any case, you can't retrieve the part if you've changed its name
                               
                        2. unmarshall it, so it is fully loaded and docx4j doesn't try to get it from the source part store
               
                                        headerPart.getContents();
                       
                           this works fine, but it is a bit opaque since it relies on a side effect / underlying knowledge of docx4j
                           
                        3. best: clone it
                        */

               
                HeaderPart newHeaderPart = new HeaderPart();
                newHeaderPart.setContents(
                                XmlUtils.deepCopy(headerPart.getContents()));
               
                //headerPart.setPartName(new PartName("/word/header.xml"));
                return wordprocessingMLPackage.getMainDocumentPart().addTargetPart(
                                newHeaderPart, AddPartBehaviour.RENAME_IF_NAME_EXISTS);

        }

        public static void createHeaderReference(
                        WordprocessingMLPackage wordprocessingMLPackage,
                        Relationship relationship) throws InvalidFormatException {

                List<SectionWrapper> sections = wordprocessingMLPackage
                                .getDocumentModel().getSections();

                SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
                // There is always a section wrapper, but it might not contain a sectPr
                if (sectPr == null) {
                        sectPr = objectFactory.createSectPr();
                        wordprocessingMLPackage.getMainDocumentPart().addObject(sectPr);
                        sections.get(sections.size() - 1).setSectPr(sectPr);
                }

                HeaderReference headerReference = objectFactory.createHeaderReference();
                headerReference.setId(relationship.getId());
                headerReference.setType(HdrFtrRef.DEFAULT);
                sectPr.getEGHdrFtrReferences().add(headerReference);// add header or
                // footer references

        }
}
 
Parsed in 0.021 seconds, using GeSHi 1.0.8.4

Re: Copy Header from a docx file to use in other while creat

PostPosted: Wed Sep 07, 2016 1:12 am
by saurabh
Hi Jason,

really thanks for your much awaited reply ! :)

there is one issue with the deepCopy method...its not copying the "image" contain in the header footer . So is there any alternative for this or how to resolve ??

also you suggested one solution to " read the header from a header.xml file stored somewhere" ..Can you please tell me how do my client create the header.xml if i ask them to share with me and I will use that header while creating new docx ?
or can we export header of existing docx file in form of xml something ??

Re: Copy Header from a docx file to use in other while creat

PostPosted: Tue Apr 16, 2019 6:30 pm
by schyzo
Hello,

I would like to up this topic, because I am having the same issue.
I am trying to copy the header from a docx to another, but I cannot keep the image.
The XmlUtils.deepCopy() only copies the text content.

Can someone help please?

Thank you very much.

Re: Copy Header from a docx file to use in other while creat

PostPosted: Tue Jun 07, 2022 10:35 am
by jonaskinny
Old post, but I too am learning this Awesome API (thank you Jason/Plutex !!) and this is what I have done re: moving a Part from one existing Package (source) to a newly created Package (target). I don't have an image (my case is a SlidePartLayout), but this may help you out. I'm not certain all is complete/correct in the resulting .ppxt does not have everything (like docProps dir that gets created when you use a tool like LibreOffice to create a .pptx etc.) but the resulting .pptx has everything I expect at this point (still learing the api), and it functions without errors.

I'm working on applying the layout to the slide ... so that is not shown below

Code: Select all
import java.io.File;

import java.net.URI;

import jakarta.xml.bind.JAXBException;

import java.lang.reflect.Method;

import org.docx4j.Docx4J;
import org.docx4j.*;
import org.docx4j.openpackaging.contenttype.ContentTypeManager;
import org.docx4j.openpackaging.contenttype.ContentTypes;
import org.docx4j.openpackaging.packages.*;
import org.docx4j.openpackaging.parts.*;
import org.docx4j.openpackaging.exceptions.*;
import org.docx4j.openpackaging.parts.JaxbXmlPart;
import org.docx4j.openpackaging.Base;
import org.pptx4j.pml.Sld;
import org.docx4j.openpackaging.parts.PresentationML.*;
import org.docx4j.relationships.*;
import org.docx4j.openpackaging.parts.relationships.*;
import org.docx4j.openpackaging.io3.stores.*;
import org.docx4j.XmlUtils;

import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;

import org.apache.log4j.Logger;
import org.pptx4j.pml.Presentation;
import org.pptx4j.pml.Shape;
import org.pptx4j.jaxb.Context;
import org.pptx4j.pml.Pic;

public class HowToPPTX {
    static {
        // Hack to force xerces since setting only in Docx4j.properties issues warnings
        System.setProperty("javax.xml.parsers.SAXParserFactory","org.apache.xerces.jaxp.SAXParserFactoryImpl");
        System.setProperty("javax.xml.parsers.DocumentBuilderFactory","org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
    }
    private static Logger log = Logger.getLogger(HowToPPTX.class);
    private static boolean MACRO_ENABLE = false;
   
    public static void main(String[] args) throws Exception {
    // output path of target Package
    String outputfilepath = System.getProperty("user.dir") + System.getProperty("file.separator") + "target.pptx";
    // source package path
    String layout_deck_path = System.getProperty("user.dir") + System.getProperty("file.separator")
              + "layouts/SM_NOTES_LAYOUTS_4_3.pptx";
    // create target package
    PresentationMLPackage pMLP = PresentationMLPackage.createPackage();
        // if we set local flag, create pptm
        if (MACRO_ENABLE) {
         ContentTypeManager ctm = pMLP.getContentTypeManager();
         ctm.removeContentType(new PartName("/ppt/presentation.xml") );
         ctm.addOverrideContentType(new URI("/ppt/presentation.xml"), ContentTypes.PRESENTATIONML_MACROENABLED);
         outputfilepath = outputfilepath.replace(".pptx",".pptm");
      }
   // get parts from the package
    MainPresentationPart presPart = (MainPresentationPart)pMLP.getParts().getParts().get(
         new PartName("/ppt/presentation.xml"));
    // dont believe this is needed or in what order ... maybe someone can confirm
    //presPart.setJaxbElement(MainPresentationPart.createJaxbPresentationElement());
    // dont believe this is needed or in what order ... maybe someone can confirm
    pMLP.addTargetPart(presPart);
    // load source package
    PresentationMLPackage lPMLP =
                (PresentationMLPackage)OpcPackage.load(new java.io.File(layout_deck_path));
    // load layout from source deck
    SlideLayoutPart layoutPart = (SlideLayoutPart)lPMLP.getParts().getParts().get(
                new PartName("/ppt/slideLayouts/slideLayout1.xml"));
    // set sourcePartStore from source to target package
    pMLP.setSourcePartStore(lPMLP.getSourcePartStore());
    // create the slideLayoutPart
    SlideLayoutPart layoutPartDeepCopy =
        (SlideLayoutPart)JaxbPmlPart.newPartForContentType(ContentTypes.PRESENTATIONML_SLIDE_LAYOUT,
        "/ppt/slideLayouts/slideLayout1.xml");
   // create the SldLayout object of the SlideLayoutPart ... the JaxbElement of the SldLayout
    // i believe this is overwritten by the below setContents() but here just incase
    //layoutPartDeepCopy.createSldLayout();
    // dont forget the contents ... we are creating the parts, then deepCopying the jaxb contents
    layoutPartDeepCopy.setContents(XmlUtils.deepCopy(layoutPart.getContents(), Context.jcPML));
   // create a new slidepart
    SlidePart slidePart = new SlidePart(new PartName("/ppt/slides/slide1.xml"));
    // create the Sld object of the SlidePart
    slidePart.setContents(SlidePart.createSld());
    // set package on newly created part before addTargetPart()
    slidePart.setPackage(pMLP);
    // add target part for Slide layout part
    slidePart.addTargetPart(layoutPartDeepCopy);
    // add SlideIdListEntry to MainPresentationPart
    presPart.addSlideIdListEntry(slidePart);
    // create and add Slide Master part
    SlideMasterPart masterPart = new SlideMasterPart();
    presPart.addSlideMasterIdListEntry(masterPart);
    // not sure below is needed
    //masterPart.setJaxbElement(masterPart.createSldMaster() );
    masterPart.addSlideLayoutIdListEntry(layoutPartDeepCopy);
    layoutPartDeepCopy.addTargetPart(masterPart);

    // create and add Theme part
    ThemePart themePart = new ThemePart(new PartName("/ppt/theme/theme1.xml"));
    java.io.InputStream is = org.docx4j.utils.ResourceUtils.getResource(
                      "org/docx4j/openpackaging/parts/PresentationML/theme.xml");
    themePart.unmarshal(is);
    // add themePart to masterPart         
    masterPart.addTargetPart(themePart);
    // add themePart to MainPresentationPart
    presPart.addTargetPart(themePart);
   
    /*      
      // Create and add shape to slide
      Shape shape = ((Shape)XmlUtils.unmarshalString(SAMPLE_SHAPE, Context.jcPML) );
      // call returns org.pptx4j.pml.Sld
      Sld sld = slidePart.getContents();
      // add shape to sld
      sld.getCSld().getSpTree().getSpOrGrpSpOrGraphicFrame().add(shape);
      // add image to slide
      addImageToSlide(pMLP,slidePart,System.getProperty("user.dir") + System.getProperty("file.separator") + "test.png");
   */
   
    // save target package
    pMLP.save(new java.io.File(outputfilepath));
   }

// the rest of this class is included incase anything here is referenced above, but should not be
// in scope for the question in this post

   private static JaxbXmlPart processJAXB(JaxbXmlPart jaxbXmlPart) throws Exception {
       log.debug("processJAXB()");
       if (jaxbXmlPart == null) throw new IllegalArgumentException("jaxbXmlPart is null");
       if (jaxbXmlPart instanceof JaxbXmlPart) {
           log.debug("JAXBXmlPart");
           if (jaxbXmlPart instanceof JaxbPmlPart) log.debug("JAXBPmlPart");
           if (jaxbXmlPart.getContents() instanceof Presentation) {
               log.debug("Presentation");
               Presentation.SldSz sldSz = ((Presentation)jaxbXmlPart.getContents()).getSldSz();
               log.debug("sldSz.getCx=" + sldSz.getCx());
                  log.debug("sldSz.getCy=" + sldSz.getCy());
                  log.debug("sldSz.getType=" + sldSz.getType());
           }
       }
       return jaxbXmlPart; 
   }
   private static JaxbXmlPart processJAXB(String filePath) throws Exception {
       PresentationMLPackage pMLP =
         (PresentationMLPackage)OpcPackage.load(new java.io.File(filePath));
         
      MainPresentationPart presPart = (MainPresentationPart)pMLP.getParts().getParts().get(
            new PartName("/ppt/presentation.xml"));   
         
      processJAXB(presPart);
      
      return presPart;
   }
   private static void addImageToSlide(PresentationMLPackage pMLP, SlidePart sld, String imgPath) throws Exception {
      
        // Add image part
        File file = new File(imgPath);
        BinaryPartAbstractImage imagePart
            = BinaryPartAbstractImage.createImagePart(pMLP, sld, file);

        // Add p:pic to slide
        sld.getJaxbElement().getCSld().getSpTree().getSpOrGrpSpOrGraphicFrame().add(
                createPicture(imagePart.getSourceRelationship().getId()));
        log.debug("added " + imgPath + " to slide");
   }
   private static Object createPicture(String relId) throws JAXBException {

        // Create p:pic         
        java.util.HashMap<String, String>mappings = new java.util.HashMap<String, String>();

        mappings.put("id1", "4");
        mappings.put("name", "Picture 3");
        mappings.put("descr", "greentick.png");
        mappings.put("rEmbedId", relId );
        mappings.put("offx", Long.toString(4214812));
        mappings.put("offy", Long.toString(3071812));
        mappings.put("extcx", Long.toString(714375));
        mappings.put("extcy", Long.toString(714375));

        return org.docx4j.XmlUtils.unmarshallFromTemplate(SAMPLE_PICTURE,
                mappings, Context.jcPML, Pic.class ) ;   


    }
   
    private static void ensurePartStore(PresentationMLPackage p) {
      PartStore targetPartStore;
         if (p.getSourcePartStore()==null) { // eg a newly created package
            log.warn("sourcePartStore undefined");
            targetPartStore = new ZipPartStore();
         } else {
            targetPartStore = p.getSourcePartStore();
            targetPartStore.setSourcePartStore(p.getSourcePartStore());
         }
         p.setTargetPartStore(targetPartStore);
    }
   
   private static String SAMPLE_SHAPE =          
      "<p:sp   xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:p=\"http://schemas.openxmlformats.org/presentationml/2006/main\">"
      + "<p:nvSpPr>"
      + "<p:cNvPr id=\"4\" name=\"Title 3\" />"
      + "<p:cNvSpPr>"
         + "<a:spLocks noGrp=\"1\" />"
      + "</p:cNvSpPr>"
      + "<p:nvPr>"
         + "<p:ph type=\"title\" />"
      + "</p:nvPr>"
   + "</p:nvSpPr>"
   + "<p:spPr />"
   + "<p:txBody>"
      + "<a:bodyPr />"
      + "<a:lstStyle />"
      + "<a:p>"
         + "<a:r>"
            + "<a:rPr lang=\"en-US\" smtClean=\"0\" />"
            + "<a:t>Hello World</a:t>"
         + "</a:r>"
         + "<a:endParaRPr lang=\"en-US\" />"
      + "</a:p>"
   + "</p:txBody>"
+ "</p:sp>";

private static String SAMPLE_PICTURE =         
          "<p:pic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:p=\"http://schemas.openxmlformats.org/presentationml/2006/main\"> "
            + "<p:nvPicPr>"
              + "<p:cNvPr id=\"${id1}\" name=\"${name}\" descr=\"${descr}\"/>"
              + "<p:cNvPicPr>"
                + "<a:picLocks noChangeAspect=\"1\"/>"
              + "</p:cNvPicPr>"
              + "<p:nvPr/>"
            + "</p:nvPicPr>"
            + "<p:blipFill>"
              + "<a:blip r:embed=\"${rEmbedId}\" cstate=\"print\"/>"
              + "<a:stretch>"
                + "<a:fillRect/>"
              + "</a:stretch>"
            + "</p:blipFill>"
            + "<p:spPr>"
              + "<a:xfrm>"
                + "<a:off x=\"${offx}\" y=\"${offy}\"/>"
                + "<a:ext cx=\"${extcx}\" cy=\"${extcy}\"/>"
              + "</a:xfrm>"
              + "<a:prstGeom prst=\"rect\">"
                + "<a:avLst/>"
              + "</a:prstGeom>"
            + "</p:spPr>"
          + "</p:pic>";
         
         
          // SCRAP NOTES
          /*
         // Slide layout part
         SlideLayoutPart layoutPart = new SlideLayoutPart();
         layoutPart.setJaxbElement( SlideLayoutPart.createSldLayout() );
         
         slidePart.addTargetPart(layoutPart);
         */

    }