Page 1 of 1

Alternating Header

PostPosted: Wed May 28, 2014 4:12 am
by kebeaner
Hi, I'm trying to get alternating headers to work
Code: Select all
      HeaderPart headerPartOdd = new HeaderPart();
      HeaderPart headerPartEven = new HeaderPart();

      Relationship relOdd = wordMLPackage.getMainDocumentPart().addTargetPart(headerPartOdd);
      Relationship relEven = wordMLPackage.getMainDocumentPart().addTargetPart(headerPartEven);

      ObjectFactory objectFactory = new ObjectFactory();

      // create header content using a header open xml skeleton
      String headerTextOdd = getXMLString("header_text_odd");
      String headerTextEven = getXMLString("header_text_even");
      // headerText = headerText.replace("productName", productName);
      
      Hdr hdrOdd = (Hdr) XmlUtils.unmarshalString(headerTextOdd);
      Hdr hdrEven = (Hdr) XmlUtils.unmarshalString(headerTextEven);
      
      headerPartOdd.setJaxbElement(hdrOdd);
      headerPartEven.setJaxbElement(hdrEven);

      List<SectionWrapper> sections = wordMLPackage.getDocumentModel().getSections();
      SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
      if (sectPr == null) {
         sectPr = objectFactory.createSectPr();
         wordMLPackage.getMainDocumentPart().addObject(sectPr);
         sections.get(sections.size() - 1).setSectPr(sectPr);
      }

      // set header reference
      HeaderReference headerReferenceOdd = objectFactory.createHeaderReference();
      headerReferenceOdd.setId(relOdd.getId());
      headerReferenceOdd.setType(HdrFtrRef.DEFAULT);

      HeaderReference headerReferenceEven = objectFactory.createHeaderReference();
      headerReferenceEven.setId(relEven.getId());
      headerReferenceEven.setType(HdrFtrRef.EVEN);

      sectPr.getEGHdrFtrReferences().add(headerReferenceEven);
      sectPr.getEGHdrFtrReferences().add(headerReferenceOdd);


but only the "even" header is showing up.
I can't seem to figure out why

Re: Alternating Header

PostPosted: Wed May 28, 2014 7:49 pm
by jason
What does the sectPr resulting XML look like?

sections.get(sections.size() - 1).setSectPr(sectPr); looks a bit dodgy...

DocumentModel has a refresh method:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
        /**
         * If you have added/deleted sections from your WordprocessingMLPackage,
         * you'll need to call this method in order for the changes to be
         * reflected in the DocumentModel.
         */

        public void refresh()
 
Parsed in 0.017 seconds, using GeSHi 1.0.8.4

Re: Alternating Header

PostPosted: Thu May 29, 2014 1:38 am
by kebeaner
sections.get(sections.size() - 1).setSectPr(sectPr); in reference to https://github.com/plutext/docx4j/blob/ ... reate.java


Code: Select all
// create header part and set relationship
      HeaderPart headerPartOdd = new HeaderPart();
      Relationship relOdd = wordMLPackage.getMainDocumentPart().addTargetPart(headerPartOdd);
      ObjectFactory objectFactory = new ObjectFactory();

      // create header content using a header open xml skeleton
      String headerTextOdd = getXMLString("header_text_odd");
      headerTextOdd = headerTextOdd.replace("productName", productName);
      Hdr hdrOdd = (Hdr) XmlUtils.unmarshalString(headerTextOdd);
      headerPartOdd.setJaxbElement(hdrOdd);

      List<SectionWrapper> sections = wordMLPackage.getDocumentModel().getSections();
      SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
      if (sectPr == null) {
         sectPr = objectFactory.createSectPr();
         wordMLPackage.getMainDocumentPart().addObject(sectPr);
         sections.get(sections.size() - 1).setSectPr(sectPr);
      }
      wordMLPackage.getDocumentModel().refresh();

      // set header reference
      HeaderReference headerReferenceOdd = objectFactory.createHeaderReference();
      headerReferenceOdd.setId(relOdd.getId());
      headerReferenceOdd.setType(HdrFtrRef.DEFAULT);
      sectPr.getEGHdrFtrReferences().add(headerReferenceOdd);

      HeaderPart headerPartEven = new HeaderPart();
      Relationship relEven = wordMLPackage.getMainDocumentPart().addTargetPart(headerPartEven);

      // create header content using a header open xml skeleton
      String headerTextEven = getXMLString("header_text_even");
      headerTextEven = headerTextEven.replace("productName", productName);
      Hdr hdrEven = (Hdr) XmlUtils.unmarshalString(headerTextEven);
      headerPartEven.setJaxbElement(hdrEven);

      // set header reference
      HeaderReference headerReferenceEven = objectFactory.createHeaderReference();
      headerReferenceEven.setId(relEven.getId());
      headerReferenceEven.setType(HdrFtrRef.EVEN);
      sectPr.getEGHdrFtrReferences().add(headerReferenceEven);

      wordMLPackage.getDocumentModel().refresh();


This only shows the even header

edit

the sectPr looks like that it should not have the same relationid right?
<w:sectPr>
<w:headerReference w:type="even" r:id="rId2"/>
<w:headerReference w:type="default" r:id="rId2"/>
<w:footerReference w:type="default" r:id="rId3"/>
<w:pgSz w:w="11907" w:h="16839" w:code="9"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"/>
</w:sectPr>


when breaking up the document with the webapp into parts, it also has does not contain a second header.xml file

Edit 2

If you have graphics in your header and you're loading it from and XML format. There doesn't seem to be a way to properly link the graphic file to the header via
XmlUtils.unmarshalString();


xml:
Code: Select all
<w:hdr xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:xml="http://www.w3.org/XML/1998/namespace">
            <w:p>
                <w:pPr>
                    <w:pStyle w:val="Header"/>
                    <w:spacing w:after="0"/>
                    <w:rPr>
                        <w:sz w:val="28"/>
                        <w:szCs w:val="28"/>
                    </w:rPr>
                </w:pPr>
                <w:r>
                    <w:rPr>
                        <w:noProof/>
                    </w:rPr>
                    <w:drawing>
                        <wp:anchor distT="0" distB="0" distL="114300" distR="114300" simplePos="false" relativeHeight="251658240" behindDoc="false" locked="false" layoutInCell="true" allowOverlap="true">
                            <wp:simplePos x="0" y="0"/>
                            <wp:positionH relativeFrom="column">
                                <wp:posOffset>4079875</wp:posOffset>
                            </wp:positionH>
                            <wp:positionV relativeFrom="paragraph">
                                <wp:posOffset>5715</wp:posOffset>
                            </wp:positionV>
                            <wp:extent cx="1678940" cy="403225"/>
                            <wp:effectExtent l="19050" t="0" r="0" b="0"/>
                            <wp:wrapSquare wrapText="bothSides"/>
                            <wp:docPr id="6" name="Picture 4" descr="Untitled.png"/>
                            <wp:cNvGraphicFramePr>
                                <a:graphicFrameLocks noChangeAspect="true"/>
                            </wp:cNvGraphicFramePr>
                            <a:graphic>
                                <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                                    <pic:pic>
                                        <pic:nvPicPr>
                                            <pic:cNvPr id="0" name="Untitled.png"/>
                                            <pic:cNvPicPr/>
                                        </pic:nvPicPr>
                                        <pic:blipFill>
                                            <a:blip r:embed="rId1"/>
                                            <a:stretch>
                                                <a:fillRect/>
                                            </a:stretch>
                                        </pic:blipFill>
                                        <pic:spPr>
                                            <a:xfrm>
                                                <a:off x="0" y="0"/>
                                                <a:ext cx="1678940" cy="403225"/>
                                            </a:xfrm>
                                            <a:prstGeom prst="rect">
                                                <a:avLst/>
                                            </a:prstGeom>
                                        </pic:spPr>
                                    </pic:pic>
                                </a:graphicData>
                            </a:graphic>
                        </wp:anchor>
                    </w:drawing>
                </w:r>
                <w:r>
                    <w:t>Insert Product Name Series</w:t>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="begin"/>
                </w:r>
                <w:r>
                    <w:instrText xml:space="preserve"> TITLE \* MERGEFORMAT </w:instrText>
                </w:r>
                <w:r>
                    <w:fldChar w:fldCharType="end"/>
                </w:r>
            </w:p>
            <w:sdt>
                <w:sdtPr>
                    <w:id w:val="8754329"/>
                    <w:comboBox>
                        <w:listItem w:value="Choose an item."/>
                    </w:comboBox>
                </w:sdtPr>
                <w:sdtContent>
                    <w:p>
                        <w:pPr>
                            <w:pStyle w:val="Header"/>
                            <w:pBdr>
                                <w:bottom w:val="single" w:color="auto" w:sz="12" w:space="1"/>
                            </w:pBdr>
                            <w:rPr>
                                <w:rFonts w:cs="Arial"/>
                                <w:sz w:val="20"/>
                            </w:rPr>
                        </w:pPr>
                        <w:r>
                            <w:t>Insert Product name, and Platform Description</w:t>
                        </w:r>
                    </w:p>
                </w:sdtContent>
            </w:sdt>
        </w:hdr>

Re: Alternating Header

PostPosted: Thu May 29, 2014 8:43 am
by jason
At this point it may be easiest if you post a complete standalone class with main method which I can run to see what is going on.

But, the note:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
        /**
         * Convenience method to add a part to this Part's
         * relationships.  The package must be set on this
         * part in order for this to work.
         *
         * The added part will replace any existing part
         * with the same name (ie same target in the rels
         * part).  In other words, if you want to use the
         * one image as the target of 2 rels, don't use
         * this method.
         *
         * @param targetpart
         *            The part to add to this part's relationships
         */

        public Relationship addTargetPart(Part targetpart) throws InvalidFormatException {
                return this.addTargetPart(targetpart, AddPartBehaviour.OVERWRITE_IF_NAME_EXISTS, null);
        }
 
Parsed in 0.013 seconds, using GeSHi 1.0.8.4


I suspect what is happening is that with new HeaderPart(), you are using the default part name, so you need to call addTargetPart with param AddPartBehaviour.RENAME_IF_NAME_EXISTS

The default is what it is, for now ancient backward compatibility reasons :-(

kebeaner wrote:If you have graphics in your header and you're loading it from and XML format. There doesn't seem to be a way to properly link the graphic file to the header via


You need to add the image part to the header part first, which will give you a rel id. For example, assuming BinaryPartAbstractImage imagePart, you'd do headerPart.addTargetPart(imagePart)

Then use that rel id in your XML, in attribute a:blip/@r:embed

Re: Alternating Header

PostPosted: Fri May 30, 2014 4:26 am
by kebeaner
The AddPartBehaviour successfully added the different header files! Hooray!
Code: Select all
      // create header part and set relationship
      HeaderPart headerPart2 = new HeaderPart();
      Relationship rel = wordMLPackage.getMainDocumentPart().addTargetPart(headerPart2, AddPartBehaviour.RENAME_IF_NAME_EXISTS);


However it does not automatically show up, (it'll show up if you go into document and manual turn on even/odd headers). I did some comparison between the two documents and I found that "evenoddheader" did not show up in the original settings.xml

Code: Select all
               <w:settings>
            <w:zoom w:percent="50"/>
            <w:defaultTabStop w:val="720"/>
            <w:evenAndOddHeaders/>
            <w:drawingGridHorizontalSpacing w:val="110"/>
            <w:displayHorizontalDrawingGridEvery w:val="2"/>
            <w:characterSpacingControl w:val="doNotCompress"/>

vs
Code: Select all
  <w:settings>
            <w:zoom w:percent="50"/>
            <w:defaultTabStop w:val="720"/>
            <w:characterSpacingControl w:val="doNotCompress"/>


How would you modify the settings to enable EvenAndOddHeaders, I've looked at example

Re: Alternating Header

PostPosted: Fri May 30, 2014 11:58 pm
by jason
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
                MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
                mdp.getDocumentSettingsPart().getContents().setEvenAndOddHeaders(new BooleanDefaultTrue());
 
Parsed in 0.013 seconds, using GeSHi 1.0.8.4

Re: Alternating Header

PostPosted: Sat May 31, 2014 12:44 am
by kebeaner
jason wrote:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
                MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
                mdp.getDocumentSettingsPart().getContents().setEvenAndOddHeaders(new BooleanDefaultTrue());
 
Parsed in 0.013 seconds, using GeSHi 1.0.8.4


The line creates a nullpointerexception error when executed.. is there a specific location which to use it in?
getdocumentSettingsPart returns null

edit

Also how would you set "first page" different header as well?

Re: Alternating Header

PostPosted: Sat May 31, 2014 7:34 am
by jason
The one liner assumes you have a document settings part, containing at least the CTSettings element. If you don't, you'll get an NPE.

It relies on the part shortcut being set, which is done as the docx is read into docx4j, or when addTargetPart is used, so either way, it *should* to be set.

What is the stack trace?

kebeaner wrote:Also how would you set "first page" different header as well?


Add the titlePg element to your sectPr

Re: Alternating Header

PostPosted: Sat May 31, 2014 7:55 am
by kebeaner
I'm creating a document from scratch, not reading it in to docx4j.

code
Code: Select all

         // creates the word document package to hold all parts
         wordMLPackage = WordprocessingMLPackage.createPackage();
         // create header, footer, cover page, health-safety page, revision page and table of
         // contents
         createHeader(wordMLPackage, productName);
         createFooter(wordMLPackage);




create header
Code: Select all
private void createHeader(WordprocessingMLPackage wordMLPackage, String productName) throws Exception {

      // The following code is heavily influenced by the official header/footer docx4j sample:
      // https://github.com/plutext/docx4j/blob/master/src/samples/docx4j/org/docx4j/samples/HeaderFooterCreate.java#L94

      // Creates Objectfactory and gets the sectPr of the document
      ObjectFactory objectFactory = new ObjectFactory();
      List<SectionWrapper> sections = wordMLPackage.getDocumentModel().getSections();
      SectPr sectPr = sections.get(sections.size() - 1).getSectPr();
      if (sectPr == null) {
         sectPr = objectFactory.createSectPr();
         wordMLPackage.getMainDocumentPart().addObject(sectPr);
         sections.get(sections.size() - 1).setSectPr(sectPr);
      }

      // generate image file as a BinaryPartAbstractImage
      ClassPathResource resource = new ClassPathResource("com/placeholder/prodweb/manual/management/exporter/docx/images/headerimage.png");
      File file = resource.getFile();
      BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, file);

      // FIRST HEADER
      // create First header part and set relationship from header to maindocument and image to
      // header
      HeaderPart headerPartEven = new HeaderPart();
      Relationship relEven = wordMLPackage.getMainDocumentPart().addTargetPart(headerPartEven);
      Relationship relImageEven = headerPartEven.addTargetPart(imagePart);

      // create header content using a header open xml skeleton
      String headerTextEven = getXMLString("headerlogo");
      headerTextEven = headerTextEven.replace("productName", productName);
      headerTextEven = headerTextEven.replace("imagerelation", relImageEven.getId());
      Hdr hdrEven = (Hdr) XmlUtils.unmarshalString(headerTextEven);
      headerPartEven.setJaxbElement(hdrEven);

      // set header reference
      HeaderReference headerReferenceEven = objectFactory.createHeaderReference();
      headerReferenceEven.setId(relEven.getId());
      headerReferenceEven.setType(HdrFtrRef.EVEN);
      sectPr.getEGHdrFtrReferences().add(headerReferenceEven);

      // OTHER HEADER
      // create header part and set relationship, where this is a second header must apply
      // AddPartBehavior.RENAME_IF_NAME_EXISTS
      HeaderPart headerPartOdd = new HeaderPart();
      Relationship relOdd = wordMLPackage.getMainDocumentPart().addTargetPart(headerPartOdd, AddPartBehaviour.RENAME_IF_NAME_EXISTS);
      Relationship relImageOdd = headerPartOdd.addTargetPart(imagePart);

      // create header content using a header open xml skeleton
      String headerTextOdd = getXMLString("headerlogoalt");
      headerTextOdd = headerTextOdd.replace("productName", productName);
      headerTextOdd = headerTextOdd.replace("imagerelation", relImageOdd.getId());
      Hdr hdrOdd = (Hdr) XmlUtils.unmarshalString(headerTextOdd);
      headerPartOdd.setJaxbElement(hdrOdd);

      // set header reference
      HeaderReference headerReferenceOdd = objectFactory.createHeaderReference();
      headerReferenceOdd.setId(relOdd.getId());
      headerReferenceOdd.setType(HdrFtrRef.DEFAULT);
      sectPr.getEGHdrFtrReferences().add(headerReferenceOdd);
   }

wordMLPackage.getMainDocumentPart().getDocumentSettingsPart().getContents().setEvenAndOddHeaders(new BooleanDefaultTrue());

Causes NPE at get contents because documentsettingspart is null.

Re: Alternating Header

PostPosted: Sat May 31, 2014 10:17 am
by jason
OK, well you need to:

- create new DocumentSettingsPart
- add content to it (a CTSettings object)
- add it to your MDP (addTargetPart)

Re: Alternating Header

PostPosted: Tue Jun 03, 2014 7:07 am
by kebeaner
Everything worked out right! Thanks for everything!