Merge multiple word documents into one Open Xml - c#

I have around 10 word documents which I generate using open xml and other stuff.
Now I would like to create another word document and one by one I would like to join them into this newly created document.
I wish to use open xml, any hint would be appreciable.
Below is my code:
private void CreateSampleWordDocument()
{
//string sourceFile = Path.Combine("D:\\GeneralLetter.dot");
//string destinationFile = Path.Combine("D:\\New.doc");
string sourceFile = Path.Combine("D:\\GeneralWelcomeLetter.docx");
string destinationFile = Path.Combine("D:\\New.docx");
try
{
// Create a copy of the template file and open the copy
//File.Copy(sourceFile, destinationFile, true);
using (WordprocessingDocument document = WordprocessingDocument.Open(destinationFile, true))
{
// Change the document type to Document
document.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
//Get the Main Part of the document
MainDocumentPart mainPart = document.MainDocumentPart;
mainPart.Document.Save();
}
}
catch
{
}
}
Update( using AltChunks):
using (WordprocessingDocument myDoc = WordprocessingDocument.Open("D:\\Test.docx", true))
{
string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2) ;
MainDocumentPart mainPart = myDoc.MainDocumentPart;
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(
AlternativeFormatImportPartType.WordprocessingML, altChunkId);
using (FileStream fileStream = File.Open("D:\\Test1.docx", FileMode.Open))
chunk.FeedData(fileStream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
mainPart.Document
.Body
.InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
mainPart.Document.Save();
}
Why this code overwrites the content of the last file when I use multiple files?
Update 2:
using (WordprocessingDocument myDoc = WordprocessingDocument.Open("D:\\Test.docx", true))
{
MainDocumentPart mainPart = myDoc.MainDocumentPart;
string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 3);
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
using (FileStream fileStream = File.Open("d:\\Test1.docx", FileMode.Open))
{
chunk.FeedData(fileStream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
mainPart.Document
.Body
.InsertAfter(altChunk, mainPart.Document.Body
.Elements<Paragraph>().Last());
mainPart.Document.Save();
}
using (FileStream fileStream = File.Open("d:\\Test2.docx", FileMode.Open))
{
chunk.FeedData(fileStream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
mainPart.Document
.Body
.InsertAfter(altChunk, mainPart.Document.Body
.Elements<Paragraph>().Last());
}
using (FileStream fileStream = File.Open("d:\\Test3.docx", FileMode.Open))
{
chunk.FeedData(fileStream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
mainPart.Document
.Body
.InsertAfter(altChunk, mainPart.Document.Body
.Elements<Paragraph>().Last());
}
}
This code is appending the Test2 data twice, in place of Test1 data as well.
Means I get:
Test
Test2
Test2
instead of :
Test
Test1
Test2

Using openXML SDK only, you can use AltChunk element to merge the multiple document into one.
This link the-easy-way-to-assemble-multiple-word-documents and this one How to Use altChunk for Document Assembly provide some samples.
EDIT 1
Based on your code that uses altchunk in the updated question (update#1), here is the VB.Net code I have tested and that works like a charm for me:
Using myDoc = DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open("D:\\Test.docx", True)
Dim altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2)
Dim mainPart = myDoc.MainDocumentPart
Dim chunk = mainPart.AddAlternativeFormatImportPart(
DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML, altChunkId)
Using fileStream As IO.FileStream = IO.File.Open("D:\\Test1.docx", IO.FileMode.Open)
chunk.FeedData(fileStream)
End Using
Dim altChunk = New DocumentFormat.OpenXml.Wordprocessing.AltChunk()
altChunk.Id = altChunkId
mainPart.Document.Body.InsertAfter(altChunk, mainPart.Document.Body.Elements(Of DocumentFormat.OpenXml.Wordprocessing.Paragraph).Last())
mainPart.Document.Save()
End Using
EDIT 2
The second issue (update#2)
This code is appending the Test2 data twice, in place of Test1 data as
well.
is related to altchunkid.
For each document you want to merge in the main document, you need to:
add an AlternativeFormatImportPart in the mainDocumentPart with an Id which must be unique. This element contains the inserted data
add in the body an Altchunk element in which you set the id to reference the previous AlternativeFormatImportPart.
In your code, you are using the same Id for all the AltChunks. It's why you see many time the same text.
I am not sure the altchunkid will be unique with your code: string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString().Substring(0, 2);
If you don't need to set a specific value, I recommend you to not set explicitly the AltChunkId when you add the AlternativeFormatImportPart. Instead, you get the one generated by the SDK like this:
VB.Net
Dim chunk As AlternativeFormatImportPart = mainPart.AddAlternativeFormatImportPart(DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML)
Dim altchunkid As String = mainPart.GetIdOfPart(chunk)
C#
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(DocumentFormat.OpenXml.Packaging.AlternativeFormatImportPartType.WordprocessingML);
string altchunkid = mainPart.GetIdOfPart(chunk);

There is a nice wrapper API (Document Builder 2.2) around open xml specially designed to merge documents, with flexibility of choosing the paragraphs to merge etc. You can download it from here (update: moved to github).
The documentation and screen casts on how to use it are here.
Update: Code Sample
var sources = new List<Source>();
//Document Streams (File Streams) of the documents to be merged.
foreach (var stream in documentstreams)
{
var tempms = new MemoryStream();
stream.CopyTo(tempms);
sources.Add(new Source(new WmlDocument(stream.Length.ToString(), tempms), true));
}
var mergedDoc = DocumentBuilder.BuildDocument(sources);
mergedDoc.SaveAs(#"C:\TargetFilePath");
Types Source and WmlDocument are from Document Builder API.
You can even add the file paths directly if you choose to as:
sources.Add(new Source(new WmlDocument(#"C:\FileToBeMerged1.docx"));
sources.Add(new Source(new WmlDocument(#"C:\FileToBeMerged2.docx"));
Found this Nice Comparison between AltChunk and Document Builder approaches to merge documents - helpful to choose based on ones requirements.
You can also use DocX library to merge documents but I prefer Document Builder over this for merging documents.
Hope this helps.

The only thing missing in these answers is the for loop.
For those who just want to copy / paste it:
void MergeInNewFile(string resultFile, IList<string> filenames)
{
using (WordprocessingDocument document = WordprocessingDocument.Create(resultFile, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = document.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
foreach (string filename in filenames)
{
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML);
string altChunkId = mainPart.GetIdOfPart(chunk);
using (FileStream fileStream = File.Open(filename, FileMode.Open))
{
chunk.FeedData(fileStream);
}
AltChunk altChunk = new AltChunk { Id = altChunkId };
mainPart.Document.Body.AppendChild(altChunk);
}
mainPart.Document.Save();
}
}
All credits go to Chris and yonexbat

Easy to use in C#:
using System;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace WordMergeProject
{
public class Program
{
private static void Main(string[] args)
{
byte[] word1 = File.ReadAllBytes(#"..\..\word1.docx");
byte[] word2 = File.ReadAllBytes(#"..\..\word2.docx");
byte[] result = Merge(word1, word2);
File.WriteAllBytes(#"..\..\word3.docx", result);
}
private static byte[] Merge(byte[] dest, byte[] src)
{
string altChunkId = "AltChunkId" + DateTime.Now.Ticks.ToString();
var memoryStreamDest = new MemoryStream();
memoryStreamDest.Write(dest, 0, dest.Length);
memoryStreamDest.Seek(0, SeekOrigin.Begin);
var memoryStreamSrc = new MemoryStream(src);
using (WordprocessingDocument doc = WordprocessingDocument.Open(memoryStreamDest, true))
{
MainDocumentPart mainPart = doc.MainDocumentPart;
AlternativeFormatImportPart altPart =
mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
altPart.FeedData(memoryStreamSrc);
var altChunk = new AltChunk();
altChunk.Id = altChunkId;
OpenXmlElement lastElem = mainPart.Document.Body.Elements<AltChunk>().LastOrDefault();
if(lastElem == null)
{
lastElem = mainPart.Document.Body.Elements<Paragraph>().Last();
}
//Page Brake einfügen
Paragraph pageBreakP = new Paragraph();
Run pageBreakR = new Run();
Break pageBreakBr = new Break() { Type = BreakValues.Page };
pageBreakP.Append(pageBreakR);
pageBreakR.Append(pageBreakBr);
return memoryStreamDest.ToArray();
}
}
}

My solution :
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace TestFusionWord
{
internal class Program
{
public static void MergeDocx(List<string> ListPathFilesToMerge, string DestinationPathFile, bool OverWriteDestination, bool WithBreakPage)
{
#region Control arguments
List<string> ListError = new List<string>();
if (ListPathFilesToMerge == null || ListPathFilesToMerge.Count == 0)
{
ListError.Add("Il n'y a aucun fichier à fusionner dans la liste passée en paramètre ListPathFilesToMerge");
}
else
{
foreach (var item in ListPathFilesToMerge.Where(x => Path.GetExtension(x.ToLower()) != ".docx"))
{
ListError.Add(string.Format("Le fichier '{0}' indiqué dans la liste passée en paramètre ListPathFilesToMerge n'a pas l'extension .docx", item));
}
foreach (var item in ListPathFilesToMerge.Where(x => !File.Exists(x)))
{
ListError.Add(string.Format("Le fichier '{0}' indiqué dans la liste passée en paramètre ListPathFilesToMerge n'existe pas", item));
}
}
if (string.IsNullOrWhiteSpace(DestinationPathFile))
{
ListError.Add("Le fichier destination FinalPathFile passé en paramètre ne peut être vide");
}
else
{
if (Path.GetExtension(DestinationPathFile.ToLower()) != ".docx")
{
ListError.Add(string.Format("Le fichier destination '{0}' indiqué dans le paramètre DestinationPathFile n'a pas l'extension .docx", DestinationPathFile));
}
if (File.Exists(DestinationPathFile) && !OverWriteDestination)
{
ListError.Add(string.Format("Le fichier destination '{0}' existe déjà. Utilisez l'argument OverWriteDestination si vous souhaitez l'écraser", DestinationPathFile));
}
}
if (ListError.Any())
{
string MessageError = "Des erreurs ont été rencontrés, détail : " + Environment.NewLine + ListError.Select(x => "- " + x).Aggregate((x, y) => x + Environment.NewLine + y);
throw new ArgumentException(MessageError);
}
#endregion Control arguments
#region Merge Files
//Suppression du fichier destination (aucune erreur déclenchée si le fichier n'existe pas)
File.Delete(DestinationPathFile);
//Création du fichier destination à vide
using (WordprocessingDocument document = WordprocessingDocument.Create(DestinationPathFile, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = document.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
document.MainDocumentPart.Document.Save();
}
//Fusion des documents
using (WordprocessingDocument myDoc = WordprocessingDocument.Open(DestinationPathFile, true))
{
MainDocumentPart mainPart = myDoc.MainDocumentPart;
Body body = mainPart.Document.Body;
for (int i = 0; i < ListPathFilesToMerge.Count; i++)
{
string currentpathfile = ListPathFilesToMerge[i];
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML);
string altchunkid = mainPart.GetIdOfPart(chunk);
using (FileStream fileStream = File.Open(currentpathfile, FileMode.Open))
chunk.FeedData(fileStream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altchunkid;
OpenXmlElement last = body.Elements().LastOrDefault(e => e is AltChunk || e is Paragraph);
body.InsertAfter(altChunk, last);
if (WithBreakPage && i < ListPathFilesToMerge.Count - 1) // If its not the last file, add breakpage
{
last = body.Elements().LastOrDefault(e => e is AltChunk || e is Paragraph);
last.InsertAfterSelf(new Paragraph(new Run(new Break() { Type = BreakValues.Page })));
}
}
mainPart.Document.Save();
}
#endregion Merge Files
}
private static int Main(string[] args)
{
try
{
string DestinationPathFile = #"C:\temp\testfusion\docfinal.docx";
List<string> ListPathFilesToMerge = new List<string>()
{
#"C:\temp\testfusion\fichier1.docx",
#"C:\temp\testfusion\fichier2.docx",
#"C:\temp\testfusion\fichier3.docx"
};
ListPathFilesToMerge.Sort(); //Sort for always have the same file
MergeDocx(ListPathFilesToMerge, DestinationPathFile, true, true);
#if DEBUG
Process.Start(DestinationPathFile); //open file
#endif
return 0;
}
catch (Exception Ex)
{
Console.Error.WriteLine(Ex.Message);
//Log exception here
return -1;
}
}
}
}

Related

Convert XML to word template using Microsoft.Office.Interop.Word

I want to convert XML to word template and when I used the code below when I open the word document it show all test like
(PK ! #qu é  [Content_Types].xml ¢(  Í•ËNÃ0E÷HüCämÕ¸ejÚ%T¢|€‰'©…c[÷‘¿gÒ´¡Ò ÚÒn"93÷Þck¤Œ–…ŽæàQY“°~Üc˜ÔJeò„½N»7, ŒÚHX ÈFÃË‹Á¤t€©
&l‚»åÓ)cëÀP%³¾Ž>çN¤ï" ~Õë]óÔš &tCåÁ†ƒ{ÈÄL‡èaI¿kYtW7VY Îi•Š#u>7ò[Jw“rÕƒSå°C)
my code like
string rootPath = #"xmlpath";
string templateDocument = #"mytemplateword documentpath";
string outputDocument = #"myoutputdocumentpath";
// word.Document wordDoc = wordApp.doc
// using (WordprocessingDocument doc =
// WordprocessingDocument.Create(xmlDataFile, WordprocessingDocumentType.Document,true))
//{
// MainDocumentPart mainPart = doc.AddMainDocumentPart();
// mainPart.Document = new Document();
// Body body = mainPart.Document.AppendChild(new Body());
// SectionProperties props = new SectionProperties();
// body.AppendChild(props);
//}
//Document doc = new Document();
string result = "";
MemoryStream mStream = new MemoryStream();
XmlTextWriter writer = new XmlTextWriter(mStream, System.Text.Encoding.Unicode);
XmlDocument document = new XmlDocument();
// XmlNodeList PatientFirst = xmlDoc.GetElementsByTagName("PatientFirst");
// XmlNodeList PatientSignatureImg = xmlDoc.GetElementsByTagName("PatientSignatureImg");
byte[] byteArray = System.IO.File.ReadAllBytes(templateDocument);
using (MemoryStream mem = new MemoryStream())
{
mem.Write(byteArray, 0, (int)byteArray.Length);
using (WordprocessingDocument Doc = WordprocessingDocument.Open(mem, true))
{
using (StreamReader reader = new StreamReader(Doc.MainDocumentPart.GetStream(FileMode.Create)))
{
documentText = reader.ReadToEnd();
}
using (StreamWriter docWriter = new StreamWriter(Doc.MainDocumentPart.GetStream(FileMode.Create)))
{
docWriter.Write(documentText);
}
}
System.IO.File.WriteAllBytes(outputDocument, mem.ToArray());

Html Text Content to Word using OpenXml

I have a rich text box which contains html formatted text as well as we can insert a copied images. I tried with AlternativeFormatImportPart and AltChunk method. It's generating the document but getting the below error. Please let me know what am I missing here.
MemoryStream ms;// = new MemoryStream(new UTF8Encoding(true).GetPreamble().Concat(Encoding.UTF8.GetBytes(h)).ToArray());
ms = new MemoryStream(HtmlToWord(fileContent));
//MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(h));
// Create alternative format import part.
AlternativeFormatImportPart chunk =
mainDocPart.AddAlternativeFormatImportPart(
"application/xhtml+xml", altChunkId);
chunk.FeedData(ms);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
public static byte[] HtmlToWord(String html)
{
const string filename = "test.docx";
if (File.Exists(filename)) File.Delete(filename);
var doc = new Document();
using (MemoryStream generatedDocument = new MemoryStream())
{
using (WordprocessingDocument package = WordprocessingDocument.Create(
generatedDocument, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = package.MainDocumentPart;
if (mainPart == null)
{
mainPart = package.AddMainDocumentPart();
new Document(new Body()).Save(mainPart);
}
HtmlConverter converter = new HtmlConverter(mainPart);
converter.ExcludeLinkAnchor = true;
converter.RefreshStyles();
converter.ImageProcessing = ImageProcessing.AutomaticDownload;
//converter.BaseImageUrl = new Uri(domainNameURL + "Images/");
converter.ConsiderDivAsParagraph = false;
Body body = mainPart.Document.Body;
var paragraphs = converter.Parse(html);
for (int i = 0; i < paragraphs.Count; i++)
{
body.Append(paragraphs[i]);
}
mainPart.Document.Save();
}
return generatedDocument.ToArray();
}
}
There are some issues in AlternativeFormatImportPart with MemoryStream, document is not getting formatted well. So followed an alternate approach, using HtmlToWord method saved the html content into word and read the file content using FileStream and feed the AlternativeFormatImportPart.
string docFileName;
HtmlToWord(fileContent, out docFileName);
FileStream fileStream = File.Open(docFileName, FileMode.Open);
// Create alternative format import part.
AlternativeFormatImportPart chunk =mainDocPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
chunk.FeedData(fileStream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;

How to convert ms word file with image and equation into html with the help memoryStream in C#

I am using as below coding and it is working fine. These programming convert word file into html file with image.
There is problem in equation.I am unable to convert ms word file equation HTML.
Can anybody help?
FileUpload1.SaveAs(Server.MapPath(FileUpload1.FileName));
string imageDirectoryName = FileUpload1.FileName + "_files";
DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath(imageDirectoryName));
if (dirInfo.Exists)
{
// Delete the directory and files.
foreach (var f in dirInfo.GetFiles())
f.Delete();
dirInfo.Delete();
}
int imageCounter = 0;
byte[] byteArray = File.ReadAllBytes(sourceDocumentFileName);
using (MemoryStream memoryStream = new MemoryStream())
{
memoryStream.Write(byteArray, 0, byteArray.Length);
using (WordprocessingDocument doc =
WordprocessingDocument.Open(memoryStream, true))
{
HtmlConverterSettings settings = new HtmlConverterSettings()
{
//PageTitle = "Test Title",
//ConvertFormatting = false,
};
XElement html = HtmlConverter.ConvertToHtml(doc, settings,
imageInfo =>
{
DirectoryInfo localDirInfo = new DirectoryInfo(Server.MapPath(imageDirectoryName));
if (!localDirInfo.Exists)
localDirInfo.Create();
++imageCounter;
string extension = imageInfo.ContentType.Split('/')[1].ToLower();
ImageFormat imageFormat = null;
if (extension == "png")
{
// Convert the .png file to a .jpeg file.
extension = "jpeg";
imageFormat = ImageFormat.Jpeg;
}
else if (extension == "bmp")
imageFormat = ImageFormat.Bmp;
else if (extension == "jpeg")
imageFormat = ImageFormat.Jpeg;
else if (extension == "tiff")
imageFormat = ImageFormat.Tiff;
else if (extension == "wmf")
imageFormat = ImageFormat.Jpeg;
else if (extension == "png")
imageFormat = ImageFormat.Png;
// If the image format is not one that you expect, ignore it,
// and do not return markup for the link.
if (imageFormat == null)
return null;
string imageFileName = imageDirectoryName + "/image" +
imageCounter.ToString() + "." + extension;
try
{
imageInfo.Bitmap.Save(Server.MapPath(imageFileName), imageFormat);
}
catch (System.Runtime.InteropServices.ExternalException)
{
return null;
}
XElement img = new XElement(Xhtml.img,
new XAttribute(NoNamespace.src, imageFileName),
imageInfo.ImgStyleAttribute,
imageInfo.AltText != null ?
new XAttribute(NoNamespace.alt, imageInfo.AltText) : null);
return img;
});
File.WriteAllText(fileInfo.Directory.FullName + "/" + fileInfo.Name.Substring(0,
fileInfo.Name.Length - fileInfo.Extension.Length) + ".html",
html.ToStringNewLineOnAttributes());
}
}
Step 1 - You should go here to get understand how to get Math object in word file here
Step 2 - Loop through Paragraphs of word file and select OfficeMath object in it, transform it to MathML (see step 1), and can transform to LaTex if you want (I think use LaTex will be friendly when use in HTML)
Note: Transform to LaTex will be similar when Transform from MMOL2MML in step 1 see here to get file
Step 3 - Insert befor/after object in step 2 a text object with content is MathML/LaTex (in step 2). Use this step because when use HtmlConverter.ConvertToHtml will miss math object in Word content so when you insert before/after object math a text will be available in HTML
This is my code:
using (WordprocessingDocument doc = WordprocessingDocument.Open(docFilePath, true))
{
foreach (var paragraph in doc.MainDocumentPart.RootElement.Descendants<Paragraph>())
{
foreach (var ele in paragraph.Descendants<DocumentFormat.OpenXml.Math.OfficeMath>())
{
string wordDocXml = ele.OuterXml;
XslCompiledTransform xslTransform = new XslCompiledTransform();
xslTransform.Load(officeMathMLSchemaFilePath);
var result = "";
using (TextReader tr = new StringReader(wordDocXml))
{
// Load the xml of your main document part.
using (XmlReader reader = XmlReader.Create(tr))
{
using (MemoryStream ms = new MemoryStream())
{
XmlWriterSettings settings = xslTransform.OutputSettings.Clone();
// Configure xml writer to omit xml declaration.
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.OmitXmlDeclaration = true;
XmlWriter xw = XmlWriter.Create(ms, settings);
// Transform our OfficeMathML to MathML.
xslTransform.Transform(reader, xw);
ms.Seek(0, SeekOrigin.Begin);
using (StreamReader sr = new StreamReader(ms, Encoding.UTF8))
{
result = MathML2Latex(sr.ReadToEnd());
officeMLFormulas.Add(result);
}
}
}
}
Run run = new Run();
run.Append(new Text(result));
ele.InsertBeforeSelf(run);
}
}
}

create word document with Open XML

I am creating a sample handler to generate simple Word document.
This document will contains the text Hello world
This is the code I use (C# .NET 3.5),
I got the Word document created but there is no text in it, the size is 0.
How can I fix it?
(I use CopyStream method because CopyTo is available in .NET 4.0 and above only.)
public class HandlerCreateDocx : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
using (MemoryStream mem = new MemoryStream())
{
// Create Document
using (WordprocessingDocument wordDocument =
WordprocessingDocument.Create(mem, WordprocessingDocumentType.Document, true))
{
// Add a main document part.
MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
// Create the document structure and add some text.
mainPart.Document = new Document();
Body body = mainPart.Document.AppendChild(new Body());
Paragraph para = body.AppendChild(new Paragraph());
Run run = para.AppendChild(new Run());
run.AppendChild(new Text("Hello world!"));
mainPart.Document.Save();
// Stream it down to the browser
context.Response.AppendHeader("Content-Disposition", "attachment;filename=HelloWorld.docx");
context.Response.ContentType = "application/vnd.ms-word.document";
CopyStream(mem, context.Response.OutputStream);
context.Response.End();
}
}
}
// Only useful before .NET 4
public void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[16 * 1024]; // Fairly arbitrary size
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
This works for me, by putting the streaming code in the outer USING block.
This causes a call to WordprocessingDocument.Close (via the Dispose method).
public void ProcessRequest(HttpContext context)
{
using (MemoryStream mem = new MemoryStream())
{
// Create Document
using (WordprocessingDocument wordDocument =
WordprocessingDocument.Create(mem, WordprocessingDocumentType.Document, true))
{
// Add a main document part.
MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
// Create the document structure and add some text.
mainPart.Document = new Document();
Body body = mainPart.Document.AppendChild(new Body());
Paragraph para = body.AppendChild(new Paragraph());
Run run = para.AppendChild(new Run());
run.AppendChild(new Text("Hello world!"));
mainPart.Document.Save();
}
context.Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
context.Response.AppendHeader("Content-Disposition", "attachment;filename=HelloWorld.docx");
mem.Seek(0, SeekOrigin.Begin);
mem.CopyTo(context.Response.OutputStream);
context.Response.Flush();
context.Response.End();
}
}
I have modifed your code to make it work. I can open it correctly after save download it.
Please see my modified below. Hope this help.
using (MemoryStream documentStream = new MemoryStream())
{
using (WordprocessingDocument myDoc = WordprocessingDocument.Create(documentStream, WordprocessingDocumentType.Document, true))
{
// Add a new main document part.
MainDocumentPart mainPart = myDoc.AddMainDocumentPart();
//Create Document tree for simple document.
mainPart.Document = new Document();
//Create Body (this element contains
//other elements that we want to include
Body body = new Body();
//Create paragraph
Paragraph paragraph = new Paragraph();
Run run_paragraph = new Run();
// we want to put that text into the output document
Text text_paragraph = new Text("Hello World!");
//Append elements appropriately.
run_paragraph.Append(text_paragraph);
paragraph.Append(run_paragraph);
body.Append(paragraph);
mainPart.Document.Append(body);
// Save changes to the main document part.
mainPart.Document.Save();
myDoc.Close();
context.Response.ClearContent();
context.Response.ClearHeaders();
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
SetContentType(context.Request, context.Response, "Simple.docx");
documentStream.Seek(0, SeekOrigin.Begin);
documentStream.CopyTo(context.Response.OutputStream);
context.Response.Flush();
context.Response.End();
}
}
string Filepath = #"C:\Users\infinity\Desktop\zoyeb.docx";
using (var wordprocessingDocument = WordprocessingDocument.Create(Filepath, DocumentFormat.OpenXml.WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = wordprocessingDocument.AddMainDocumentPart();
mainPart.Document = new DocumentFormat.OpenXml.Wordprocessing.Document();
Body body = mainPart.Document.AppendChild(new Body());
DocumentFormat.OpenXml.Wordprocessing.Paragraph para = body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
DocumentFormat.OpenXml.Wordprocessing.Run run = para.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Run());
run.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Text("siddiq"));
wordprocessingDocument.MainDocumentPart.Document.Save();
}
go to nuget package manager and install this first into your project
Install-Package DocumentFormat.OpenXml -Version 2.8.1

openxml-sdk - Creating word 2007 file with settings.xml

I am trying to generate a new Word document using the following code. The Word document gets generated without settings.xml. I need to have settings.xml in the word file. Any help would be appreciated.
public static byte[] GenerateNewDocument()
{
byte[] returnValue = null;
MemoryStream stream = null;
WordprocessingDocument wordDoc = null;
try
{
stream = new System.IO.MemoryStream();
wordDoc = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document);
}
catch
{
if (stream != null)
{
stream.Close();
}
throw;
}
using (wordDoc)
{
wordDoc.AddMainDocumentPart();
MainDocumentPart mainPart = wordDoc.MainDocumentPart;
mainPart.Document = new Document(new Body());
mainPart.Document.Save();
}
returnValue = stream.ToArray();
return returnValue;
}
You need to create your own DocumentSettingsPart and then insert it into the MainDocumentPart. So the settings part may look like this:
<w:settings xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vm" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main">
<w:defaultTabStop w:val="475"/>
<w:compat>
<w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="14"/>
</w:compat>
</w:settings>
And then having that saved somewhere as "settings.xml", you could use code like this:
private static void AddSettingsToMainDocumentPart(MainDocumentPart part)
{
DocumentSettingsPart settingsPart = part.AddNewPart<DocumentSettingsPart>();
FileStream settingsTemplate = new FileStream("settings.xml", FileMode.Open, FileAccess.Read);
settingsPart.FeedData(settingsTemplate);
settingsPart.Settings.Save();
}

Categories

Resources