Copy Header and Footer to all other Documents OpenXML
Asked Answered
B

2

5

We have a master docx with the header and footer in and nothing else (formatted with images). We have 100s of word documents with body content but no header and footer and we want to be able to process these when we populate them and add the header and footer from the master header and footer docx.

I have looked at the MSDN documentation here: https://msdn.microsoft.com/en-us/library/cc546917.aspx but it doesn't seem to work and when I open the target document the formatting is wrong and the images are missing.

Is there a way to make this exactly copy the header and footer from one document to another?

Brader answered 4/10, 2017 at 8:25 Comment(0)
C
6

I also had to implement this for a client at work. I'll give you the methods I wrote for headers and footers.

I wrote trying to keep all styles, fonts, dimensions and images inside header and footer.

This is the method that i use to attach header to another docx.

Try to understand reading the comments I've written.

headerTemplatePath: path of docx where take header

documentPath: path of docx where append header

    public void PrependHeader(string headerTemplatePath, string documentPath)
    {
        // Open docx where we need to add header
        using (var wdDoc = WordprocessingDocument.Open(documentPath, true))
        {
            var mainPart = wdDoc.MainDocumentPart;

            // Delete exist header
            mainPart.DeleteParts(mainPart.HeaderParts);

            // Create new header
            var headerPart = mainPart.AddNewPart<HeaderPart>();

            // Get id of new header
            var rId = mainPart.GetIdOfPart(headerPart);

            // Open the header document to be copied
            using (var wdDocSource = WordprocessingDocument.Open(headerTemplatePath, true))
            {
                // Get header part
                var firstHeader = wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();
                if (firstHeader != null)
                {
                    // Copy content of header to new header
                    headerPart.FeedData(firstHeader.GetStream());
                    // Keep formatting
                    foreach (var childElement in headerPart.Header.Descendants<Paragraph>())
                    {
                        var paragraph = (Paragraph) childElement;
                        if (paragraph.ParagraphProperties.SpacingBetweenLines == null)
                        {
                            paragraph.ParagraphProperties.SpacingBetweenLines = new SpacingBetweenLines
                            {
                                After = "0"
                            };
                            paragraph.ParagraphProperties.ParagraphStyleId = new ParagraphStyleId
                            {
                                Val = "No Spacing"
                            };
                        }
                    }
                    // Get all ids of every 'Parts'
                    var listToAdd = new List<KeyValuePair<Type, Stream>>();
                    foreach (var idPart in firstHeader.Parts)
                    {
                        var part = firstHeader.GetPartById(idPart.RelationshipId);
                        if (part is ImagePart)
                        {
                            headerPart.AddNewPart<ImagePart>("image/png", idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (ImagePart), part.GetStream()));
                        }
                        else if (part is DiagramStylePart)
                        {
                            headerPart.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
                        }
                        else if (part is DiagramColorsPart)
                        {
                            headerPart.AddNewPart<DiagramColorsPart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramColorsPart),
                                part.GetStream()));
                        }
                        else if (part is DiagramDataPart)
                        {
                            headerPart.AddNewPart<DiagramDataPart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramDataPart), part.GetStream()));
                        }
                        else if (part is DiagramLayoutDefinitionPart)
                        {
                            headerPart.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
                        }
                        else if (part is DiagramPersistLayoutPart)
                        {
                            headerPart.AddNewPart<DiagramPersistLayoutPart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramPersistLayoutPart),
                                part.GetStream()));
                        }
                    }
                    // Foreach Part, copy stream to new header
                    var i = 0;
                    foreach (var idPart in headerPart.Parts)
                    {
                        var part = headerPart.GetPartById(idPart.RelationshipId);
                        if (part.GetType() == listToAdd[i].Key)
                        {
                            part.FeedData(listToAdd[i].Value);
                        }
                        i++;
                    }
                }
                else
                {
                    mainPart.DeleteParts(mainPart.HeaderParts);
                    var sectToRemovePrs = mainPart.Document.Body.Descendants<SectionProperties>();
                    foreach (var sectPr in sectToRemovePrs)
                    {
                        // Delete reference of old header
                        sectPr.RemoveAllChildren<HeaderReference>();
                    }
                    return;
                }
            }

            // Get all sections, and past header to each section (Page)
            var sectPrs = mainPart.Document.Body.Descendants<SectionProperties>();
            foreach (var sectPr in sectPrs)
            {
                // Remove old header reference 
                sectPr.RemoveAllChildren<HeaderReference>();
                // Add new header reference
                sectPr.PrependChild(new HeaderReference { Id = rId });
            }
        }
    }

Footer method:

footerTemplatePath: path of docx where take footer

documentPath: path of docx where append footer

    public void PrependFooter(string footerTemplatePath, string documentPath)
    {
        // Open docx where append footer
        using (var wdDoc = WordprocessingDocument.Open(documentPath, true))
        {
            var mainPart = wdDoc.MainDocumentPart;

            // Remove exist footer
            mainPart.DeleteParts(mainPart.FooterParts);

            // Create new footer
            var footerParts = mainPart.AddNewPart<FooterPart>();

            // Get Id of new footer
            var rId = mainPart.GetIdOfPart(footerParts);

            // Open the footer document to be copied
            using (var wdDocSource = WordprocessingDocument.Open(footerTemplatePath, true))
            {
                var firstFooter = wdDocSource.MainDocumentPart.FooterParts.LastOrDefault();
                if (firstFooter != null)
                {
                    // Copy content of footer
                    footerParts.FeedData(firstFooter.GetStream());
                    // Keep formatting
                    foreach (var childElement in footerParts.Footer.Descendants<Paragraph>())
                    {
                        var paragraph = (Paragraph) childElement;
                        if (paragraph.ParagraphProperties.SpacingBetweenLines == null)
                        {
                            paragraph.ParagraphProperties.SpacingBetweenLines = new SpacingBetweenLines
                            {
                                After = "0"
                            };
                            paragraph.ParagraphProperties.ParagraphStyleId = new ParagraphStyleId
                            {
                                Val = "No Spacing"
                            };
                        }
                    }
                    // Create list of Parts ID needed to new footer
                    var listToAdd = new List<KeyValuePair<Type, Stream>>();
                    foreach (var idPart in firstFooter.Parts)
                    {
                        var part = firstFooter.GetPartById(idPart.RelationshipId);
                        if (part is ImagePart)
                        {
                            footerParts.AddNewPart<ImagePart>("image/png", idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (ImagePart), part.GetStream()));
                        }
                        else if (part is DiagramStylePart)
                        {
                            footerParts.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
                        }
                        else if (part is DiagramColorsPart)
                        {
                            footerParts.AddNewPart<DiagramColorsPart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramColorsPart),
                                part.GetStream()));
                        }
                        else if (part is DiagramDataPart)
                        {
                            footerParts.AddNewPart<DiagramDataPart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramDataPart), part.GetStream()));
                        }
                        else if (part is DiagramLayoutDefinitionPart)
                        {
                            footerParts.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
                        }
                        else if (part is DiagramPersistLayoutPart)
                        {
                            footerParts.AddNewPart<DiagramPersistLayoutPart>(idPart.RelationshipId);
                            listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramPersistLayoutPart),
                                part.GetStream()));
                        }
                    }
                    // Foreach ID, copy stream to new footer
                    var i = 0;
                    foreach (var idPart in footerParts.Parts)
                    {
                        var part = footerParts.GetPartById(idPart.RelationshipId);
                        if (part.GetType() == listToAdd[i].Key)
                        {
                            part.FeedData(listToAdd[i].Value);
                        }
                        i++;
                    }
                }
                else
                {
                    mainPart.DeleteParts(mainPart.FooterParts);
                    var sectToRemovePrs = mainPart.Document.Body.Descendants<SectionProperties>();
                    foreach (var sectPr in sectToRemovePrs)
                    {
                        // Delete reference of footer
                        sectPr.RemoveAllChildren<FooterReference>();
                    }
                    return;
                }
            }

            // Get all sections, and past footer to each section (Page)
            var sectPrs = mainPart.Document.Body.Descendants<SectionProperties>();
            foreach (var sectPr in sectPrs)
            {
                // Delete old reference
                sectPr.RemoveAllChildren<FooterReference>();
                // Add new footer reference
                sectPr.PrependChild(new FooterReference { Id = rId });
            }
        }
    }

Sorry for my English, if you have any questions, let me know.

Bye.

Cathead answered 4/10, 2017 at 8:55 Comment(4)
How can I insert html string in to the header?Grounds
This has worked well for me but it doesn't seem to copy the existing font and size from the source document if it is based on a styleIndigent
This is absolutely wonderful. I can see it is taken from MSDN and then added to. Why on EARTH isn't this part of Microsoft's example?? Good work.Weak
@Weak Thank you bud, I don't know why it's not in Microsoft's example.Cathead
B
1

I've recently been working on a similar solution to what @stfno.me's answer has above, however I've updated it to account for a number of areas it doesn't account for.

After referencing the original Microsoft Learn guide here, I noticed a couple of things:

  1. A Word document can have multiple headers defined, which internally result in multiple header XML files. Each of these represents the first, default and even headers respectively, which are set via the options in Word for creating different headers for odd/even pages and a different first page header. The examples I've seen only do a .FirstOrDefault on the HeaderParts of a document, which means only one of those headers is being accounted for.

  2. The code I found isn't easy to follow, and requires some separation. I took the liberty of creating 'bite-sized' methods to allow them to be easily called.

I also found that I wanted to handle the case of documents potentially having existing headers/footers on them, or none at all, and thus always pre-emptively delete the headers/footers before copying the source material over.

I have noticed an issue in this regard where there's a possibility of the HeaderReference of the older headers remaining in the document, which is unusual since I do find all references of HeaderReferences in the SectionProperties and remove them, but shouldn't be a common problem.

The below methods are my solution, and can be simply updated to use a FooterPart instead of a HeaderPart to apply the same changes to the footer. I literally copy/pasted these functions and found + replaced 'Header' with 'Footer'.

For simplicity - 'target' refers to the target document that needs a header and footer, 'source' refers to the document that has the header and footer, but no other content.

Hope this saves someone else the pain of figuring this out

The top-level method for replacing a header:

public void ReplaceHeaders(string sourceFilePath, string targetFilePath) {
        using (WordprocessingDocument sourceDocument = WordprocessingDocument.Open(sourceFilePath, false))
        using (WordprocessingDocument targetDocument = WordprocessingDocument.Open(targetFilePath, true))
        {
            MainDocumentPart mainPart = targetDocument.MainDocumentPart;

            DeleteHeaders(targetDocument);

            CreateOrUpdateHeaders(sourceDocument, targetDocument);

            targetDocument.Save();
        }
    }

Delete Headers method:

private void DeleteHeaders(WordprocessingDocument document)
    {
        MainDocumentPart mainPart = document.MainDocumentPart;

        mainPart.DeleteParts(mainPart.HeaderParts);
        IEnumerable<SectionProperties> sectPrs = mainPart.Document.Body.Elements<SectionProperties>();
        foreach (var sectPr in sectPrs)
        {
            sectPr.RemoveAllChildren<HeaderReference>();
        }
    }

CreateOrUpdateHeaders method:

private void CreateOrUpdateHeaders(WordprocessingDocument sourceDocument, WordprocessingDocument targetDocument)
    {
        MainDocumentPart targetMainPart = targetDocument.MainDocumentPart;
        MainDocumentPart sourceMainPart = sourceDocument.MainDocumentPart;

        foreach (var sourceHeaderPart in sourceMainPart.HeaderParts)
        {
            var sourceHeaderReference = sourceDocument.MainDocumentPart.Document.Descendants<HeaderReference>()
            .First(hr => hr.Id.Value == sourceDocument.MainDocumentPart.GetIdOfPart(sourceHeaderPart));
            var sourceHeaderReferenceType = sourceHeaderReference.Type;

            var targetHeaderReferences = targetMainPart.Document.Descendants<HeaderReference>();

            HeaderPart targetHeaderPart = targetMainPart.AddNewPart<HeaderPart>();
            var targetHeaderPartId = targetMainPart.GetIdOfPart(targetHeaderPart);

            targetHeaderPart.FeedData(sourceHeaderPart.GetStream());

            SectionProperties sectionProperties = targetMainPart.Document.Body.Elements<SectionProperties>().First();
            PageMargin pageMargin = new PageMargin() { Header = 0, Footer = 0, Gutter = (UInt32Value)0U }; // Not necessary, used to remove default spacing above header and below footer

            sectionProperties.Append(new HeaderReference() { Type = sourceHeaderReferenceType, Id = targetHeaderPartId });
            sectionProperties.Append(pageMargin);

            CopyHeaderContentParts(sourceHeaderPart, targetHeaderPart);
        }
    }

CopyHeaderContentParts method (taken from @stfno.me's answer):

    private void CopyHeaderContentParts(HeaderPart sourceHeaderPart, HeaderPart targetHeaderPart)
    {
        var listToAdd = new List<KeyValuePair<Type, Stream>>();
        foreach (var idPart in sourceHeaderPart.Parts)
        {
            var part = sourceHeaderPart.GetPartById(idPart.RelationshipId);
            if (part is ImagePart)
            {
                targetHeaderPart.AddNewPart<ImagePart>("image/png", idPart.RelationshipId);
                listToAdd.Add(new KeyValuePair<Type, Stream>(typeof(ImagePart), part.GetStream()));
            }
            else if (part is DiagramStylePart)
            {
                targetHeaderPart.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
                listToAdd.Add(new KeyValuePair<Type, Stream>(typeof(DiagramStylePart), part.GetStream()));
            }
            else if (part is DiagramColorsPart)
            {
                targetHeaderPart.AddNewPart<DiagramColorsPart>(idPart.RelationshipId);
                listToAdd.Add(new KeyValuePair<Type, Stream>(typeof(DiagramColorsPart),
                    part.GetStream()));
            }
            else if (part is DiagramDataPart)
            {
                targetHeaderPart.AddNewPart<DiagramDataPart>(idPart.RelationshipId);
                listToAdd.Add(new KeyValuePair<Type, Stream>(typeof(DiagramDataPart), part.GetStream()));
            }
            else if (part is DiagramLayoutDefinitionPart)
            {
                targetHeaderPart.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
                listToAdd.Add(new KeyValuePair<Type, Stream>(typeof(DiagramStylePart), part.GetStream()));
            }
            else if (part is DiagramPersistLayoutPart)
            {
                targetHeaderPart.AddNewPart<DiagramPersistLayoutPart>(idPart.RelationshipId);
                listToAdd.Add(new KeyValuePair<Type, Stream>(typeof(DiagramPersistLayoutPart),
                    part.GetStream()));
            }
        }

        var i = 0;
        foreach (var idPart in targetHeaderPart.Parts)
        {
            var part = targetHeaderPart.GetPartById(idPart.RelationshipId);
            if (part.GetType() == listToAdd[i].Key)
            {
                part.FeedData(listToAdd[i].Value);
            }
            i++;
        }
    }
Buxtehude answered 15/3, 2023 at 9:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.