none
Problems replacing the Header in a Word Document RRS feed

  • Question

  • The article "How to: Replace the Header in a Word Processing Document" http://msdn.microsoft.com/en-us/library/office/cc546917.aspx almost completely satisfies my requirement, except that it did not take the Header options or 'Type' into account.

    If I modify the part where the header reference is added to the section properties to include a header option, the header is no longer visible on any pages of the document, whereas previously it could be seen on all pages.

     sectionProperties.Append(new HeaderReference()
     {
         Id = destinationHeaderPartId,
         Type = HeaderFooterValues.First
     });

    If I open up the header with Word 2007 and tick the 'Different First Page' box, the header that I attempted to include now becomes visible.

    Clearly this is not an automated solution, so I looked for further help in the article "Generating Documents with Headers and Footers in Word 2007 by Using the Open XML SDK 2.0 for Microsoft Office" http://msdn.microsoft.com/en-us/library/office/ee355228%28v=office.12%29.aspx

    This worked fine for me and used a similar construction to add the header reference to the section properties.

    So then I attempted to perform the same HeaderPart generation, as in the article and adding this to the MainDocumentPart of the document in the original filepathTo, but that did not work with the Type = HeaderFooterValues.First.

    I then attempted to generate the body of the document only (no headers or footers), as described in the second article and then used this document as the 'filepathTo' and re-worked the code from the first article with the Type = HeaderFooterValues.First modification and this worked.

    So what I have here is that I can merge a header from one document into a document generated by Open XML SDK 2.0 including the Type attribute, but I cannot get the same result merging the same header into a Word 2007 document.

    I would be grateful for some assistance.


    AlanNHBC

    Thursday, November 1, 2012 6:07 AM

Answers

  • Hi Alan

    With something like this I think you're going to have to do some nitty-gritty detective work. Create "identical" files in Word 2007 and Word 2010 (as a normal user), then compare the document.xml where the headers are defined to see how Word 2007 does it differently.

    Or, create the Word 2010 document as a user and open it in Word 2007. If you can see the header the way you expect, make a small change to the file, save as, close, then compare its document.xmls to that of the original.

    In either case, you'll probably end up having to pass in the xml string defining the elements and attributes in order to create the file the way Word 2007 expects it. Quite possibly, such a file will open in Word 2010 in Compatibility Mode.

    Word 2007 was the first version with the XML file formats and it definitely had some "hiccups", especially where the Open XML SDK is concerned (that was designed for 2010). This apparently is one of the inconsistencies...


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, November 2, 2012 4:55 PM
    Moderator

All replies

  • Hi AlanNHBC,

    Thanks for posting in the MSDN Forum.

    It's based on my experience that your description will not be in theory. Would you please share your code for further research. I will provide the code to general a Header for Word document I hope it can help you.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Wordprocessing;
    using com.mksword.Net.OpenXmlTools;
    
    namespace ConsoleApplication9
    {
        class Class1 : WordprocessingDocumentUtil 
        {
            public void Action()
            {
                OpenedDocumentHandler(AddHeader, true);
            }
    
            private bool AddHeader(WordprocessingDocument WDP)
            {
                bool result = false;
                MainDocumentPart MDP = WDP.MainDocumentPart;
                Document Doc = MDP.Document;
                SectionProperties SPs = Doc.Descendants<SectionProperties>()
                    .First();
                SPs.RemoveAllChildren();
                MDP.DeleteParts<HeaderPart>(MDP.HeaderParts);
                HeaderPart HP = MDP.AddNewPart<HeaderPart>();
                Header H = new Header();
                Paragraph P = new Paragraph();
                Run R = new Run();
                Text T = new Text() { Text = "Test it" };
                R.Append(T);
                P.Append(R);
                H.Append(P);
                HP.Header = H;
                string rId = MDP.GetIdOfPart(HP);
                HeaderReference HR = new HeaderReference()
                {
                    Type = HeaderFooterValues.Default,
                    Id = rId
                };
                SPs.Append(HR);
                HeaderPart HP1 = MDP.AddNewPart<HeaderPart>();
                Header H1 = new Header();
                Paragraph P1 = new Paragraph();
                Run R1 = new Run();
                Text T1 = new Text() { Text = "Test First" };
                R1.Append(T1);
                P1.Append(R1);
                H1.Append(P1);
                HP1.Header = H1;
                string rId1 = MDP.GetIdOfPart(HP1);
                HeaderReference HR1 = new HeaderReference()
                {
                    Type = HeaderFooterValues.First,
                    Id = rId1
                };
                SPs.Append(HR1);
                // This is a very important part for your issue. for more infomration
                // Please look at http://msdn.microsoft.com/en-us/library/cc546917.aspx
                // For the same result if you want to create Even Odd head, evenAndOddHeaders
                // must be set.
                TitlePage TP = new TitlePage();
                SPs.Append(TP);
                H1.Save();
                return result;
            }
        }
    }

    Have a good day,

    Tom


    Tom Xu [MSFT]
    MSDN Community Support | Feedback to us

    Friday, November 2, 2012 6:39 AM
    Moderator
  • Tom,

    Thanks for your response. The code you have provided is similar to the article "Generating Documents with Headers and Footers in Word 2007 by Using the Open XML SDK 2.0 for Microsoft Office" http://msdn.microsoft.com/en-us/library/office/ee355228%28v=office.12%29.aspx which generates a document with headers and footers from OpenXML SDK.

    I mentioned in my original post that I had got this working 'straight from the box'.

    However what I am trying to do is to extract the Header (and eventually Footer) from one document into another document. The reason for this is to have a variety of Header / Footer options which can be mixed and matched into a variety of letter templates which will finally replace any place holders with custom data.

    The code below is modelled on "How to: Replace the Header in a Word Processing Document" http://msdn.microsoft.com/en-us/library/office/cc546917.aspx with the minor modification to only use the header on the first page only.

    As I wrote earlier, when I run the code below with a 'header' document and another document created using OpenXML SDK (see other code below), I get the intended result.

    If however I create a Word 2007 document which is intended to be exactly the same layout as the OpenXML SDK generated document, the header is not visible.

    The 'header' document in my simple test is created by Word 2007 by clicking in the header area and adding the text "Header for page 1 only." The "Different first page" is also set. I will eventually be extracting the HeaderReference Type from the 'header' document, but for simplicity I am 'hard coding' it here. Note that if I remove the Type = HeaderFooterValues.First from the HeaderReference, I can see the Header on all pages whether the target document is generated by Word 2007 or by OpenXML SDK.

    Header merge code from one document into another

    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Wordprocessing;

    namespace SimpleDocCreation
    {
        class StevenDemoModified
        {
            public static void AddHeaderFromTo(string filepathFrom, string filepathTo)
            {
                // Replace header in target document with header of source document.

                using (WordprocessingDocument
                    wdDoc = WordprocessingDocument.Open(filepathTo, true))
                {
                    MainDocumentPart mainPart = wdDoc.MainDocumentPart;

                    // Delete the existing header part.
                    mainPart.DeleteParts(mainPart.HeaderParts);

                    // Create a new header part.
                    DocumentFormat.OpenXml.Packaging.HeaderPart headerPart = mainPart.AddNewPart<HeaderPart>();

                    // Get Id of the headerPart.
                    string rId = mainPart.GetIdOfPart(headerPart);

                    // Feed target headerPart with source headerPart.
                    using (WordprocessingDocument wdDocSource =
                        WordprocessingDocument.Open(filepathFrom, true))
                    {
                        DocumentFormat.OpenXml.Packaging.HeaderPart firstHeader = wdDocSource.MainDocumentPart.HeaderParts.First();
                        wdDocSource.MainDocumentPart.HeaderParts.First();

                        if (firstHeader != null)
                        {
                            headerPart.FeedData(firstHeader.GetStream());
                        }

                         //Get SectionProperties and Replace HeaderReference with new Id.
                        IEnumerable<DocumentFormat.OpenXml.Wordprocessing.SectionProperties> sectPrs =
                            mainPart.Document.Body.Elements<SectionProperties>();

                        foreach (var sectPr in sectPrs)
                        {
                            // Delete existing references to headers.
                            sectPr.RemoveAllChildren<HeaderReference>();

                            // Create the new header reference node.
                            // Only Change from existing code!!

                            HeaderReference headerReference = new HeaderReference()
                            {
                                Id = rId,
                                Type = HeaderFooterValues.First
                            };
                            sectPr.PrependChild<HeaderReference>(headerReference);
                        }
                    }
                }
            }
        }
    }

    Code to generate a simple two page document using OpenXML SDK

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Wordprocessing;
    using DocumentFormat.OpenXml;

     

    namespace SimpleDocCreation
    {
        class TwoPageDocGenerator
        {
            public static void AddParts(WordprocessingDocument parent)
            {
                var mainDocumentPart = parent.AddMainDocumentPart();

                GenerateMainDocumentPart().Save(mainDocumentPart);
            }

            private static Document GenerateMainDocumentPart()
            {
                var element =
                    new Document(
                        new Body(
                            new Paragraph(
                                new Run(
                                    new Text("Page 1 content"))
                            ),
                            new Paragraph(
                                new Run(
                                    new Break() { Type = BreakValues.Page })
                            ),
                            new Paragraph(
                                new Run(
                                    new LastRenderedPageBreak(),
                                    new Text("Page 2 content"))
                            ),
                            new SectionProperties(
                                new PageMargin()
                                {
                                    Top = 1440,
                                    Right = (UInt32Value)1440UL,
                                    Bottom = 1440,
                                    Left = (UInt32Value)1440UL,
                                    Header = (UInt32Value)720UL,
                                    Footer = (UInt32Value)720UL,
                                    Gutter = (UInt32Value)0UL
                                },
                                new TitlePage()
                            )));

                return element;
            }
        }
    }


    AlanNHBC

    Friday, November 2, 2012 11:44 AM
  • Hi Alan

    With something like this I think you're going to have to do some nitty-gritty detective work. Create "identical" files in Word 2007 and Word 2010 (as a normal user), then compare the document.xml where the headers are defined to see how Word 2007 does it differently.

    Or, create the Word 2010 document as a user and open it in Word 2007. If you can see the header the way you expect, make a small change to the file, save as, close, then compare its document.xmls to that of the original.

    In either case, you'll probably end up having to pass in the xml string defining the elements and attributes in order to create the file the way Word 2007 expects it. Quite possibly, such a file will open in Word 2010 in Compatibility Mode.

    Word 2007 was the first version with the XML file formats and it definitely had some "hiccups", especially where the Open XML SDK is concerned (that was designed for 2010). This apparently is one of the inconsistencies...


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, November 2, 2012 4:55 PM
    Moderator
  • Thanks for your reply Cindy.

    We have a large number of letter templates, most of which were originally created using Word 97. These have been converted to the OpenXML format in several ways:

    • Using some Microsoft conversion utility which I believe was available before Word 2007 was released. (Sorry I am unable to find what this was, as it is no longer in use)
    • Opening the W97 document in Word 2007 and saving as DOCX
    • Using Sharepoint 2010 Word Automation Services to convert from W97 to DOCX

    Am I likely to achieve Word 2010 compatibility by converting any DOCX produced by the first two methods to DOCX using Sharepoint 2010 Word Automation Services?

    My assumption here is that the Word Automation Services reads in a variety of formats into some internal format and then writes it out to the chosen output format without any reference to the input format. If it merely copies the input DOCX to the output DOCX, then obviously this would not serve any purpose.

    I am also assuming that documents produced in Word 2010 should be able to be opened in Word 2007, providing no new features have been used.


    AlanNHBC

    Wednesday, November 7, 2012 4:07 PM
  • Hi Alan

    I'm sorry, I have no knowledge of what the Automation Services actually do to the files they "Save As".

    Nor am I aware of any specific issues with opening Word 2010 documents in Word 2007, but it may be that some will start to appear as more people move to 2010.

    What I do know is that Word 97, similar to 2007, was what many people termed a "public beta version". It was the first version to implement a new file format, as well as many other new things, and a number of issues showed up as it came into general use. These weren't fixed in Word 97, but in the next version, Word 2000. If you have files coming directly from Word 97 there is the possibility that they are slightly "damaged", which could cause issues during the conversion to a much newer version (and different file format).


    Cindy Meister, VSTO/Word MVP, my blog

    Thursday, November 8, 2012 6:44 AM
    Moderator