Update Memorystream when replacing Bookmark

Asked

Viewed 121 times

0

Guys, I’m doing a job RESTFUL in C# that has a method that receives a byte array of a document WORD, and in this document I need to replace existing bookmarks with text that are also passed in the method.

  • Problem : When performing the replacement of bookmarks by the appropriate text I cannot update the Memorystream to obtain the byte array updated with file modifications. Someone has already had to work with

  • Referential

    public class ReferenciaRelatorio
    {
           public string referencia {get; set;}
           public object valor { get; set; }
     }
    
  • Reporteriods

     [DataContract]
     public class RelatorioDS
     {        
         [DataMember]
         public List<ReferenciaRelatorio> mapaDeSubstituicao { get; set; }
         /**arquivo binario na base 64**/
        [DataMember]
        public string template { get; set; }
     }
    
  • Geradorrelatorioword (EDITED)

    using System;
    using System.IO;
    
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Microsoft.Office.Interop.Word;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Wordprocessing;
    using DocumentFormat.OpenXml;
    
    
    
    namespace RestService
    {
    public class GeradorRelatorioWord 
    {
    
       public ResponseData gerarRelatorio(RelatorioDS data)
       {
          ResponseData resposta =  new ResponseData();
          try
          {
             byte[] saida = null;
             byte[] template = System.Convert.FromBase64String(data.template);
             using (MemoryStream mem = new MemoryStream(template))
             {
                /**EDITADO**/
                /**mem.Write(template, 0, (int)template.Length);**/
               using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, false))
               {
                 var bookMarks = recuperarBookMark(wordDoc.MainDocumentPart.Document);
                 substituirBookMark(data, bookMarks);
                 byte[] buf;  
                 Stream stream = wordDoc.MainDocumentPart.GetStream();
                 buf = new byte[stream.Length];  
                 stream.Read(buf, 0, buf.Length);
                 saida = buf ;
    
    
                 /** EDITADO **/
                 /**
                 wordDoc.MainDocumentPart.Document.Save();
                 wordDoc.Close();
                 using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
                 {
                   string documentoTexto = sr.ReadToEnd();
    
                   using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
                   {
                     sw.Write(documentoTexto);
    
                     MemoryStream me = new MemoryStream();
                     sw.BaseStream.CopyTo(me);
                     saida = me.ToArray();
                   }
    
    
                 }**/
    
               }
               resposta.relatorio = System.Convert.ToBase64String(saida);
    
             }
        }
        catch(Exception e)
        {
    
          resposta.erros.Add(new MensagemErro(e));
    
        }
        return resposta;
       }
    
       /**
       * Recupera os BookMarks que existirem
       **/
       private Dictionary<string, BookmarkEnd> recuperarBookMark(OpenXmlElement documentPart, Dictionary<string, BookmarkEnd> results = null, Dictionary<string, string> unmatched = null)
       {
          results = results ?? new Dictionary<string, BookmarkEnd>();
          unmatched = unmatched ?? new Dictionary<string, string>();
    
          foreach (var child in documentPart.Elements())
          {
              if (child is BookmarkStart)
              {
                var bStart = child as BookmarkStart;
                unmatched.Add(bStart.Id, bStart.Name);
              }
    
              if (child is BookmarkEnd)
              {
                var bEnd = child as BookmarkEnd;
                foreach (var orphanName in unmatched)
                {
                 if (bEnd.Id == orphanName.Key)
                 results.Add(orphanName.Value, bEnd);
                }
              }
    
              recuperarBookMark(child, results, unmatched);
          }
    
          return results;
       }
    
       /**
       * substitui os bookmarks
       *
       *
       **/
       private static void substituirBookMark(RelatorioDS data, Dictionary<string, BookmarkEnd> bookMarks)
       {
          foreach (var end in bookMarks)
          {
            string bookmark = Uri.UnescapeDataString(end.Key);
            foreach (ReferenciaRelatorio entry in data.mapaDeSubstituicao)
            {
              if (bookmark.Equals(entry.referencia))
              {
                var textElement = new Text((string)entry.valor);
                var runElement = new Run(textElement);
    
                end.Value.InsertAfterSelf(runElement);
              }
    
            }
    
          }
       }
    
    
    }
    }
    

1 answer

1

Your code dealing with the stream has some problems:

First: when you write on stream mem the stream cursor is at the end of the stream, which can cause your reading to fail. Tip: change the code snippet

byte[] template = System.Convert.FromBase64String(data.template);
using (MemoryStream mem = new MemoryStream())
{
    mem.Write(template, 0, (int)template.Length);
    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, true))

for

byte[] template = System.Convert.FromBase64String(data.template);
using (MemoryStream mem = new MemoryStream(template))
{
    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, false))

Second: the word document stream is not necessarily text; use a StreamReader and converting to text (using UTF-8 or other default encoding) will likely cause data loss. Swap the snippet

using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
    string documentoTexto = sr.ReadToEnd();
    using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
    {
        sw.Write(documentoTexto);
        MemoryStream me = new MemoryStream();
        sw.BaseStream.CopyTo(me);
        saida = me.ToArray();
    }
}

for

using (var mem = new MemoryStream()) {
    wordDoc.MainDocumentPart.GetStream().ToArray().CopyTo(mem);
    saida = mem.ToArray();
}
  • thanks for the tips. Just a doubt,I think the Stream class does not have the Toarray method. I made the changes to your answer, however the file I get from byte array it gets corrupted. @carlosfigueira

  • Ah, this is a Extension method that I have in my library. You can copy to a memory stream using the CopyTo then.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.