Corrupt document after calling AddAlternativeForma

2019-04-09 03:23发布

问题:

I am trying to create an AddAlternativeFormatImportPart in a .docx file in order to reference it in the document via an AltChunk. the problem is that the code below causes the docx file to read as corrupted by Word and cannot be opened.

        string html = "some html code."

        string altChunkId = "html234";
        var document = WordprocessingDocument.Open(inMemoryPackage, true);
        var mainPart = document.MainDocumentPart.Document;
        var mainDocumentPart = document.MainDocumentPart;

        AlternativeFormatImportPart chunk = mainDocumentPart.AddAlternativeFormatImportPart
            (AlternativeFormatImportPartType.Xhtml, altChunkId);

        Stream contentStream = chunk.GetStream(FileMode.Open,FileAccess.ReadWrite);
        StreamWriter contentWriter = new StreamWriter(contentStream);
        contentWriter.Write(html);
        contentWriter.Flush();

        {
          ...
        }

        mainPart.Save();

回答1:

I think it might be how you are handeling the stream from the AlternativeFormatImportPart. Try using FeedData instead, like in my example below.

        StringBuilder xhtmlBuilder = new StringBuilder();
        xhtmlBuilder.Append("<html>");
        xhtmlBuilder.Append("<body>");
        xhtmlBuilder.Append("<b>Hello world!</b>");
        xhtmlBuilder.Append("</body>");
        xhtmlBuilder.Append("</html>");

        using (WordprocessingDocument doc = WordprocessingDocument.Open(inputFilePath, true))
        {
            string altChunkId = "chunk1";
            AlternativeFormatImportPart chunk = doc.MainDocumentPart.AddAlternativeFormatImportPart
                (AlternativeFormatImportPartType.Xhtml, altChunkId);

            using (MemoryStream xhtmlStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xhtmlBuilder.ToString())))
            {
                chunk.FeedData(xhtmlStream);

                AltChunk altChunk = new AltChunk();
                altChunk.Id = altChunkId;
                doc.MainDocumentPart.Document.Body.Append(altChunk);
            }

            doc.MainDocumentPart.Document.Save();

        }


回答2:

I think it is because you cannot import an AltChunk into a document that is opened from a memory stream. I had the same issue. I was opening the template from a memory stream like so:

Private Sub UpdateDoc(templatePath As String)
    Using fs As FileStream = File.OpenRead(templatePath)
        Using ms As New MemoryStream
            CopyStream(fs, ms)
            Using doc As WordprocessingDocument = WordprocessingDocument.Open(ms, True)
                'update the document
                doc.MainDocumentPart.Document.Save()
            End Using
        End Using
    End Using
End Sub

Private Sub CopyStream(source As Stream, target As Stream)
    Dim buffer() As Byte
    Dim bytesRead As Integer = 1

    ReDim buffer(32768)

    While bytesRead > 0
        bytesRead = 0
        bytesRead = source.Read(buffer, 0, buffer.Length)
        target.Write(buffer, 0, bytesRead)
    End While
End Sub

This works for normal updates of content controls etc. and document is fine when streamed back to client or saved as docx. But it corrupts doc when inserting an AltChunk.

Opening a doc from a physical file path works when inserting AltChunk like so:

    Using doc As WordprocessingDocument = WordprocessingDocument.Open(strTempFile, True)
        Dim altChunkId As String = "AltChunkId1"
        Dim mainDocPart As MainDocumentPart = doc.MainDocumentPart

        Dim chunk As AlternativeFormatImportPart = mainDocPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Xhtml,
                                                                altChunkId)
        Dim strHTML As String = "<html><head/><body><h1>Html Heading</h1><p>This is an html document in a string literal.</p></body></html>"
        Using chunkStream As Stream = chunk.GetStream(FileMode.Create, FileAccess.Write)
            Using sr As StreamWriter = New StreamWriter(chunkStream)
                sr.Write(strHTML)
            End Using
        End Using

        Dim altChunk As New AltChunk
        altChunk.Id = altChunkId

        mainDocPart.Document.Body.InsertAfter(altChunk, mainDocPart.Document.Body.Elements(Of Paragraph)().Last())
        mainDocPart.Document.Save()
    End Using

It seems you cannot import an AltChunk into a memory stream, you can only do it when you open the physical file for writing. Can anyone shed some light on this matter?



回答3:

I know this is an old post, but i have the same issue. When using AltChunk in file, it works but not when in MemoryStream. It would be great if anyone knows anything about this. This is how i initiate the WordprocessingDocument

var byteArrayWithFileFrom360 = ProcessFileHandler.GetFileContent(204735);

var wordDocMemoryStream = new MemoryStream();
wordDocMemoryStream.Write(byteArrayWithFileFrom360, 0, byteArrayWithFileFrom360.Length);

var myDoc = WordprocessingDocument.Open(wordDocMemoryStream, true);