Sheinar
Sheinar

Reputation: 402

“corrupt” document when Streaming In Memory Merge Word Document using OpenXML

I am trying merge several Word Document using OpenXML on ASP.NET MVC 5. But I am constantly getting a message from Microsoft Word that the document is corrupt.

private Stream GenerateDocument(DocumentType documentType)
{
    using (var templateStream = File.OpenRead(GetTemplatePath(documentType)))
    {
        //some code
        var result = documentGenerator.Generate();
        return result;
    }
}

private Stream MergeDocuments(DocumentLibraryModel documentLibrary)
{
    var documentTypes = documentLibrary.DocumentTypes.GetEnumerator();
    var mainStream = GenerateDocument(documentTypes.Current);

    using (WordprocessingDocument mainDocument = WordprocessingDocument.Open(mainStream, true))
    {

        XElement newBody = XElement.Parse(mainDocument.MainDocumentPart.Document.Body.OuterXml);
        documentTypes.MoveNext();
        while (documentTypes.MoveNext())
        {
            WordprocessingDocument tempDocument = WordprocessingDocument.Open(GenerateDocument(documentTypes.Current), true);
            XElement tempBody = XElement.Parse(tempDocument.MainDocumentPart.Document.Body.OuterXml);

            newBody.Add(tempBody);
            mainDocument.MainDocumentPart.Document.Body = new Body(newBody.ToString());
            mainDocument.MainDocumentPart.Document.Save();
            mainDocument.Package.Flush();
        }

    }

    return mainStream;
}

However the document opens as corrupted.

Any ideas?

Upvotes: 1

Views: 346

Answers (1)

MarkoR
MarkoR

Reputation: 553

Problem lies in this:

XElement tempBody = XElement.Parse(tempDocument.MainDocumentPart.Document.Body.OuterXml);    
newBody.Add(tempBody);

You are adding body to body which generates invalid Word document. Word document can contain only one Body at the time.

I would recommend cloning elements instead of parsing XML. You can do this:

using (WordprocessingDocument mainDocument = WordprocessingDocument.Open(mainStream, true))
{
    mainDocument.MainDocumentPart.Document.Body = new Body();

    documentTypes.MoveNext();
    while (documentTypes.MoveNext())
    {
        using (WordprocessingDocument tempDocument = WordprocessingDocument.Open(GenerateDocument(documentTypes.Current)))
        {
            foreach (var element in tempDocument.MainDocumentPart.Document.Body.Elements)
            {
                mainDocument.MainDocumentPart.Document.Body.AppendChild(element.CloneNode(true));
            }
        }
    }

    mainDocument.MainDocumentPart.Document.Save();
}

Upvotes: 1

Related Questions