1
votes

I am currently working on a program in which a user should be able to merge several Word documents into one, without losing any formatting, headers and so on. The documents should simply stack up, one after another, without any changes.

Here is my current code:

public virtual Byte[] MergeWordFiles(IEnumerable<SendData> sourceFiles)
{
    int f = 0;
    // If only one Word document then skip merge.
    if (sourceFiles.Count() == 1)
    {
        return sourceFiles.First().File;
    }
    else
    {
        MemoryStream destinationFile = new MemoryStream();

        // Add first file
        var firstFile = sourceFiles.First().File;

        destinationFile.Write(firstFile, 0, firstFile.Length);
        destinationFile.Position = 0;

        int pointer = 1;
        byte[] ret;

        // Add the rest of the files
        try
        {
            using (WordprocessingDocument mainDocument = WordprocessingDocument.Open(destinationFile, true))
            {
                XElement newBody = XElement.Parse(mainDocument.MainDocumentPart.Document.Body.OuterXml);

                for (pointer = 1; pointer < sourceFiles.Count(); pointer++)
                {
                    WordprocessingDocument tempDocument = WordprocessingDocument.Open(new MemoryStream(sourceFiles.ElementAt(pointer).File), true);
                    XElement tempBody = XElement.Parse(tempDocument.MainDocumentPart.Document.Body.OuterXml);
                    newBody.Add(XElement.Parse(new DocumentFormat.OpenXml.Wordprocessing.Paragraph(new Run(new Break { Type = BreakValues.Page })).OuterXml));
                    newBody.Add(tempBody);

                    mainDocument.MainDocumentPart.Document.Body = new Body(newBody.ToString());
                    mainDocument.MainDocumentPart.Document.Save();
                    mainDocument.Package.Flush();
                }
            }
        }
        catch (OpenXmlPackageException oxmle)
        {
            throw new Exception(string.Format(CultureInfo.CurrentCulture, "Error while merging files. Document index {0}", pointer), oxmle);
        }
        catch (Exception e)
        {
            throw new Exception(string.Format(CultureInfo.CurrentCulture, "Error while merging files. Document index {0}", pointer), e);
        }
        finally
        {
            ret = destinationFile.ToArray();
            destinationFile.Close();
            destinationFile.Dispose();
        }

        return ret;
    }
}

The problem here is that the formatting is copied from the first document and applied to all the rest, meaning that for instance a different header in the second document will be ignored. How do I prevent this?

I have been looking in to breaking the document in to sections using SectionMarkValues.NextPage, as well as using altChunk.

The problem with the latter is altChunk does not seem to be able to handle a MemoryStream into its "FeedData" method.

1
What's your SendData object? - Blue Eyed Behemoth
The SendData type contains information used later on in the program (such as whether the file should be saved to disc or sent via email). The merging only require the File attribute, which contains the document in byte array format. - Johan Hager

1 Answers

0
votes

DocIO is a .NET library that can read, write, merge and render Word 2003/2007/2010/2013/2016 files. The whole suite of controls is available for free (commercial applications also) through the community license program if you qualify. The community license is the full product with no limitations or watermarks.

Step 1: Create a console application
Step 2: Add reference to Syncfusion.DocIO.Base, Syncfusion.Compression.Base and Syncfusion.OfficeChart.Base; You can add these reference to your project using NuGet also.
Step 3: Copy & paste the following code snippet.

This code snippet will produce the document as per your requirement; each input Word document will get merged with its original formatting, styles and headers/footer.

using Syncfusion.DocIO.DLS;
using Syncfusion.DocIO;
using System.IO;

namespace DocIO_MergeDocument
{
class Program
{
    static void Main(string[] args)
    {
        //Boolean to indicate whether any of the input document has different odd and even headers as true
        bool isDifferentOddAndEvenPagesEnabled = false;
        // Creating a new document.
        using (WordDocument mergedDocument = new WordDocument())
        {
            //Get the files from input directory
            DirectoryInfo dirInfo = new DirectoryInfo(System.Environment.CurrentDirectory + @"\..\..\Data");
            FileInfo[] fileInfo = dirInfo.GetFiles();
            for (int i = 0; i < fileInfo.Length; i++)
            {
                if (fileInfo[i].Extension == ".doc" || fileInfo[i].Extension == ".docx")
                {
                    using (WordDocument sourceDocument = new WordDocument(fileInfo[i].FullName))
                    {
                        //Check whether the document has different odd and even header/footer
                        if (!isDifferentOddAndEvenPagesEnabled)
                        {
                            foreach (WSection section in sourceDocument.Sections)
                            {
                                isDifferentOddAndEvenPagesEnabled = section.PageSetup.DifferentOddAndEvenPages;
                                if (isDifferentOddAndEvenPagesEnabled)
                                    break;
                            }
                        }
                        //Sets the breakcode of First section of source document as NoBreak to avoid imported from a new page
                        sourceDocument.Sections[0].BreakCode = SectionBreakCode.EvenPage;
                        //Imports the contents of source document at the end of merged document
                        mergedDocument.ImportContent(sourceDocument, ImportOptions.KeepSourceFormatting);
                    }
                }
            }
            //if any of the input document has different odd and even headers as true then
            //Copy the content of the odd header/foort and add the copied content into the even header/footer
            if (isDifferentOddAndEvenPagesEnabled)
            {
                foreach (WSection section in mergedDocument.Sections)
                {
                    section.PageSetup.DifferentOddAndEvenPages = true;
                    if (section.HeadersFooters.OddHeader.Count > 0 && section.HeadersFooters.EvenHeader.Count == 0)
                    {
                        for (int i = 0; i < section.HeadersFooters.OddHeader.Count; i++)
                            section.HeadersFooters.EvenHeader.ChildEntities.Add(section.HeadersFooters.OddHeader.ChildEntities[i].Clone());
                    }
                    if (section.HeadersFooters.OddFooter.Count > 0 && section.HeadersFooters.EvenFooter.Count == 0)
                    {
                        for (int i = 0; i < section.HeadersFooters.OddFooter.Count; i++)
                            section.HeadersFooters.EvenFooter.ChildEntities.Add(section.HeadersFooters.OddFooter.ChildEntities[i].Clone());
                    }
                }
            }
            //If there is no document to merge then add empty section with empty paragraph
            if (mergedDocument.Sections.Count == 0)
                mergedDocument.EnsureMinimal();
            //Saves the document in the given name and format
            mergedDocument.Save("result.docx", FormatType.Docx);
        }
    }
}

}

Downloadable Demo

Note: There is a Word document (not section) level settings for applying different header/footer for odd and even pages. Each input document can have different values for this property. if any of the input document has different odd and even header/footer as true, it will affect the visual appearance of header/footer in the resultant document. Hence, if any of the input document has different odd and even header/footer, then the resultant Word document will have been replaced with the odd header/footer contents.

For further information about DocIO, please refer our help documentation

Note: I work for Syncfusion