Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Word file is corrupted after replacing the header in a word document which has section breaks using Open XML SDK #1864

Closed
JSydney04 opened this issue Jan 26, 2025 · 2 comments
Assignees

Comments

@JSydney04
Copy link

JSydney04 commented Jan 26, 2025

Describe the bug
Hi, I am using the replace the header in a word processing document code which uses two documents. The header in fromFile.docx to be replaced in toFile.docx. The file toFile.docx already have section breaks. The section breaks can be added using Layout tab in word, select Breaks --> Section Breaks--> Next Page and save the document. After the header replacement code execution the toFile.docx became corrupted. Facing this issue and how this can be fixed. The code is given below.

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

string fromFile = @"C:\Users\jhe\Desktop\LearnAndTech\HeaderAndFooter\MSDNTest\fromFile.docx";
string toFile = @"C:\Users\jhe\Desktop\LearnAndTech\HeaderAndFooter\MSDNTest\toFile.docx";

AddHeaderFromTo(fromFile, toFile);


static void AddHeaderFromTo(string fromFile, string toFile)
{
    // Replace header in target document with header of source document.
    using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(toFile, true))
    using (WordprocessingDocument wdDocSource = WordprocessingDocument.Open(fromFile, true))
    {
        if (wdDocSource.MainDocumentPart is null || wdDocSource.MainDocumentPart.HeaderParts is null)
        {
            throw new ArgumentNullException("MainDocumentPart and/or HeaderParts is null.");
        }

        if (wdDoc.MainDocumentPart is null)
        {
            throw new ArgumentNullException("MainDocumentPart is null.");
        }

        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.

        DocumentFormat.OpenXml.Packaging.HeaderPart? firstHeader = wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();

        wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();

        if (firstHeader is not null)
        {
            headerPart.FeedData(firstHeader.GetStream());
        }

        if (mainPart.Document.Body is null)
        {
            throw new ArgumentNullException("Body is null.");
        }

        // 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.
            sectPr.PrependChild<HeaderReference>(new HeaderReference() { Id = rId });
        }
    }
}

To Reproduce
Create fromFile.docx and toFile.docx files with headers.
Add section breaks to toFile.docx. The section breaks can be added using Layout tab in word, select Breaks --> Section Breaks--> Next Page and save the document. Execute the above code.

Observed behavior
A popup will be shown while opening the toFile.docx after the above code execution which says 'word found unreadable contents in toFile.docx. Do you want to recover the contents of this document? '.

Expected behavior
Open the file without corruption or any error,

Desktop (please complete the following information):

  • OS: Windows 10
  • Office version : Microsoft 365 Apps for enterprise Version 2412
  • .NET Target: any
  • DocumentFormat.OpenXml Version: 3.2.0

Thanks in advance.

@JSydney04 JSydney04 changed the title Word file is corrupted when replace the header in a word document which has section breaks, using Open XML SDK for replacing header Word file is corrupted after replacing the header in a word document which has section breaks using Open XML SDK Jan 26, 2025
@mikeebowen mikeebowen self-assigned this Jan 27, 2025
@mikeebowen
Copy link
Collaborator

mikeebowen commented Jan 27, 2025

Hi @sani-j,

The section break is a red herring in this case. There are 2 issues with your code. First SectionProperties is not a direct descendant of the Body and the Elements method only finds immediate child elements. If you want to find elements at any level you should use .Descendants.

So, update your code to read:

IEnumerable<DocumentFormat.OpenXml.Wordprocessing.SectionProperties> sectPrs = mainPart.Document.Body.Descendants<SectionProperties>();

Also, the Type property on the HeaderReference is required. So, when you add your new HeaderReference add the Type Property as below:

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

If you run into similar issues in the future, you can use the OpenXmlValidator Class to find these issues. Or if you prefer a UI. I created a wrapper for the Validator in VSCode: OOXML Validator.

Below is the code from your earlier post updated with the fixes. Since this has been answered, I will close this issue.

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

string fromFile = @"C:\path\to\fromFile.docx";
string toFile = @"C:\path\to\toFile.docx";

AddHeaderFromTo(fromFile, toFile);


static void AddHeaderFromTo(string fromFile, string toFile)
{
    // Replace header in target document with header of source document.
    using (WordprocessingDocument wdDocTo = WordprocessingDocument.Open(toFile, true))
    using (WordprocessingDocument wdDocFrom = WordprocessingDocument.Open(fromFile, true))
    {
        if (wdDocFrom.MainDocumentPart is null || wdDocFrom.MainDocumentPart.HeaderParts is null)
        {
            throw new ArgumentNullException("MainDocumentPart and/or HeaderParts is null.");
        }

        if (wdDocTo.MainDocumentPart is null)
        {
            throw new ArgumentNullException("MainDocumentPart is null.");
        }

        MainDocumentPart mainPart = wdDocTo.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.

        DocumentFormat.OpenXml.Packaging.HeaderPart? firstHeader = wdDocFrom.MainDocumentPart.HeaderParts.FirstOrDefault();

        wdDocFrom.MainDocumentPart.HeaderParts.FirstOrDefault();

        if (firstHeader is not null)
        {
            headerPart.FeedData(firstHeader.GetStream());
        }

        if (mainPart.Document.Body is null)
        {
            throw new ArgumentNullException("Body is null.");
        }

        // Get SectionProperties and Replace HeaderReference with new Id.
        // Elements gets only direct children, use Descendants instead to find at any level
        IEnumerable<DocumentFormat.OpenXml.Wordprocessing.SectionProperties> sectPrs = mainPart.Document.Body.Descendants<SectionProperties>();
        foreach (var sectPr in sectPrs)
        {
            sectPr.RemoveAllChildren<HeaderReference>();

            // Create the new header reference node.
            sectPr.PrependChild<HeaderReference>(new HeaderReference() { Id = rId, Type = HeaderFooterValues.Default }); // This needs the Type to be valid
        }
    }
}

@JSydney04
Copy link
Author

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants