xceed texto reemplazar novacode generate documento create crear archivos c# openxml docx

texto - using novacode c#



AƱada varios archivos DOCX juntos (7)

Necesito usar C # programáticamente para agregar varios archivos docx preexistentes en un archivo docx largo y único, incluyendo marcas especiales como viñetas e imágenes. La información de encabezado y pie de página se eliminará, por lo que no estará disponible para causar ningún problema.

Puedo encontrar mucha información sobre la manipulación de un archivo docx individual con .NET Framework 3, pero nada fácil u obvio acerca de cómo fusionaría los archivos. También hay un programa de terceros (Acronis.Words) que lo hará, pero es prohibitivamente caro.

Actualizar:

Se ha sugerido automatizar a través de Word, pero mi código se ejecutará en ASP.NET en un servidor web IIS, por lo que ir a Word no es una opción para mí. Perdón por no mencionar eso en primer lugar.


Hace un tiempo, escribí una pequeña aplicación de prueba para hacer esto. Mi aplicación de prueba trabajó con documentos de Word 2003 (.doc) no .docx, pero me imagino que el proceso es el mismo: creo que todo lo que tendría que cambiar es usar una versión más nueva del ensamblado de interoperabilidad primaria. Este código se vería mucho mejor con las nuevas características de C # 4.0 ...

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Office.Interop.Word; using Microsoft.Office.Core; using System.Runtime.InteropServices; using System.IO; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { new Program().Start(); } private void Start() { object fileName = Path.Combine(Environment.CurrentDirectory, @"NewDocument.doc"); File.Delete(fileName.ToString()); try { WordApplication = new ApplicationClass(); var doc = WordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing); try { doc.Activate(); AddDocument(@"D:/Projects/WordTests/ConsoleApplication1/Documents/Doc1.doc", doc, false); AddDocument(@"D:/Projects/WordTests/ConsoleApplication1/Documents/Doc2.doc", doc, true); doc.SaveAs(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); } finally { doc.Close(ref missing, ref missing, ref missing); } } finally { WordApplication.Quit(ref missing, ref missing, ref missing); } } private void AddDocument(string path, Document doc, bool lastDocument) { object subDocPath = path; var subDoc = WordApplication.Documents.Open(ref subDocPath, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing); try { object docStart = doc.Content.End - 1; object docEnd = doc.Content.End; object start = subDoc.Content.Start; object end = subDoc.Content.End; Range rng = doc.Range(ref docStart, ref docEnd); rng.FormattedText = subDoc.Range(ref start, ref end); if (!lastDocument) { InsertPageBreak(doc); } } finally { subDoc.Close(ref missing, ref missing, ref missing); } } private static void InsertPageBreak(Document doc) { object docStart = doc.Content.End - 1; object docEnd = doc.Content.End; Range rng = doc.Range(ref docStart, ref docEnd); object pageBreak = WdBreakType.wdPageBreak; rng.InsertBreak(ref pageBreak); } private ApplicationClass WordApplication { get; set; } private object missing = Type.Missing; } }


No necesita usar la automatización. Los archivos DOCX se basan en los formatos OpenXML. Son solo archivos zip con un montón de partes XML y binarias (archivos Think) dentro. Puede abrirlos con la API de empaquetado (System.IO.Packaging en WindowsBase.dll) y manipularlos con cualquiera de las clases XML en el Framework.

Visita OpenXMLDeveloper.org para más detalles.


Su complejo de abandono por lo que el código está fuera del alcance de una publicación en el foro, estaría escribiendo su aplicación para usted, pero en resumen.

  • Abra ambos documentos como Paquetes
  • Pasa por las partes del segundo docuemnt en busca de imágenes y cosas embebidas
  • Agregue estas partes al primer paquete recordando las nuevas ID de relación (esto implica mucho trabajo de transmisión)
  • abra la parte document.xml en el segundo documento y reemplace todas las antiguas ID de relación con las nuevas: añada todos los nodos secundarios, pero no el nodo raíz, del segundo documento.xml al primer documento.xml
  • guarde todos los XmlDocuments y elimine el paquete

Hice una aplicación en C # para combinar archivos RTF en un solo documento. Espero que también funcione para los archivos DOC y DOCX.

Word._Application wordApp; Word._Document wordDoc; object outputFile = outputFileName; object missing = System.Type.Missing; object vk_false = false; object defaultTemplate = defaultWordDocumentTemplate; object pageBreak = Word.WdBreakType.wdPageBreak; string[] filesToMerge = new string[pageCounter]; filestoDelete = new string[pageCounter]; for (int i = 0; i < pageCounter; i++) { filesToMerge[i] = @"C:/temp/temp" + i.ToString() + ".rtf"; filestoDelete[i] = @"C:/temp/temp" + i.ToString() + ".rtf"; } try { wordDoc = wordApp.Documents.Add(ref missing, ref missing, ref missing, ref missing); } catch(Exception ex) { Console.WriteLine(ex.Message); } Word.Selection selection= wordApp.Selection; foreach (string file in filesToMerge) { selection.InsertFile(file, ref missing, ref missing, ref missing, ref missing); selection.InsertBreak(ref pageBreak); } wordDoc.SaveAs(ref outputFile, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);

¡Espero que esto ayude!


Desea utilizar AltChunks y OpenXml SDK 1.0 (como mínimo, 2.0 si puede). ¡Mira el blog de Eric White para más detalles y solo como un gran recurso! Aquí hay una muestra de código que debería comenzar, si no funciona inmediatamente.

public void AddAltChunkPart(Stream parentStream, Stream altStream, string altChunkId) { //make sure we are at the start of the stream parentStream.Position = 0; altStream.Position = 0; //push the parentStream into a WordProcessing Document using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(parentStream, true)) { //get the main document part MainDocumentPart mainPart = wordDoc.MainDocumentPart; //create an altChunk part by adding a part to the main document part AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(altChunkPartType, altChunkId); //feed the altChunk stream into the chunk part chunk.FeedData(altStream); //create and XElement to represent the new chunk in the document XElement newChunk = new XElement(altChunk, new XAttribute(relId, altChunkId)); //Add the chunk to the end of the document (search to last paragraph in body and add at the end) wordDoc.MainDocumentPart.GetXDocument().Root.Element(body).Elements(paragraph).Last().AddAfterSelf(newChunk); //Finally, save the document wordDoc.MainDocumentPart.PutXDocument(); } //reset position of parent stream parentStream.Position = 0; }


Esta es una pregunta muy tardía a la original y bastante ha cambiado, pero pensé que compartiría la forma en que escribí mi lógica de fusión. Esto hace uso de Open XML Power Tools

public byte[] CreateDocument(IList<byte[]> documentsToMerge) { List<Source> documentBuilderSources = new List<Source>(); foreach (byte[] documentByteArray in documentsToMerge) { documentBuilderSources.Add(new Source(new WmlDocument(string.Empty, documentByteArray), false)); } WmlDocument mergedDocument = DocumentBuilder.BuildDocument(documentBuilderSources); return mergedDocument.DocumentByteArray; }

Actualmente esto está funcionando muy bien en nuestra aplicación. He cambiado un poco el código porque mis requisitos son que cada documento que se debe procesar primero. Entonces, lo que se transfiere es un objeto DTO con la matriz de bytes de la plantilla y los diversos valores que deben reemplazarse. Así es como se ve mi código actualmente. Lo cual lleva el código un poco más allá.

public byte[] CreateDocument(IList<DocumentSection> documentTemplates) { List<Source> documentBuilderSources = new List<Source>(); foreach (DocumentSection documentTemplate in documentTemplates.OrderBy(dt => dt.Rank)) { // Take the template replace the items and then push it into the chunk using (MemoryStream templateStream = new MemoryStream()) { templateStream.Write(documentTemplate.Template, 0, documentTemplate.Template.Length); this.ProcessOpenXMLDocument(templateStream, documentTemplate.Fields); documentBuilderSources.Add(new Source(new WmlDocument(string.Empty, templateStream.ToArray()), false)); } } WmlDocument mergedDocument = DocumentBuilder.BuildDocument(documentBuilderSources); return mergedDocument.DocumentByteArray; }


A pesar de todas las buenas sugerencias y soluciones presentadas, desarrollé una alternativa. En mi opinión, debe evitar usar Word en aplicaciones de servidor por completo. Así que trabajé con OpenXML, pero no funcionó con AltChunk. Agregué texto al cuerpo original, recibí una Lista de bytes [] en lugar de una Lista de nombres de archivos pero puede cambiar fácilmente el código según sus necesidades.

using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Xml.Linq; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; namespace OfficeMergeControl { public class CombineDocs { public byte[] OpenAndCombine( IList<byte[]> documents ) { MemoryStream mainStream = new MemoryStream(); mainStream.Write(documents[0], 0, documents[0].Length); mainStream.Position = 0; int pointer = 1; byte[] ret; try { using (WordprocessingDocument mainDocument = WordprocessingDocument.Open(mainStream, true)) { XElement newBody = XElement.Parse(mainDocument.MainDocumentPart.Document.Body.OuterXml); for (pointer = 1; pointer < documents.Count; pointer++) { WordprocessingDocument tempDocument = WordprocessingDocument.Open(new MemoryStream(documents[pointer]), 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(); } } } catch (OpenXmlPackageException oxmle) { throw new OfficeMergeControlException(string.Format(CultureInfo.CurrentCulture, "Error while merging files. Document index {0}", pointer), oxmle); } catch (Exception e) { throw new OfficeMergeControlException(string.Format(CultureInfo.CurrentCulture, "Error while merging files. Document index {0}", pointer), e); } finally { ret = mainStream.ToArray(); mainStream.Close(); mainStream.Dispose(); } return (ret); } } }

Espero que esto te ayude.