Generate docx from dotx without Microsoft Interop - c#

I am using this code to replace 2 words and produce a *.doc (destinationFile) file from a *.dotx (sourceFile) file .
Dictionary<string, string> keyValues = new Dictionary<string, string>();
keyValues.Add("xxxxReplacethat1", "replaced1");
keyValues.Add("xxxxReplacethat2", "replaced2");
File.Copy(sourceFile, destinationFile, true);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(destinationFile, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
foreach (KeyValuePair<string, string> item in keyValues)
{
Regex regexText = new Regex(item.Key);
docText = regexText.Replace(docText, item.Value);
}
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
How I can modify this code to produce a *.docx because I need to append some lines to the *.docx file in another function.
I don't want to use Microsoft Interop because I don't want to install it on server.

Did this myself a couple of weeks ago.
Copy the file first then open the copy and change it's document type
var template = #"SourceTemplate.dotx";
var destinationFile = #"DestinationFile.docx";
File.Copy(template, destinationFile);
using (WordprocessingDocument document = WordprocessingDocument.Open(destinationFile, true)) {
// Change the document's type here
document.ChangeDocumentType(WordprocessingDocumentType.Document);
// Do any additional processing here
document.Close();
}

Related

ZIP related exception after saving WordprocessingDocument

I am trying to replace text in a docx document based on this sample, with some modifications: https://learn.microsoft.com/en-us/office/open-xml/how-to-search-and-replace-text-in-a-document-part#sample-code
However, the saved document is not valid anymore. Word is able to correct the file, but there is a Number of entries expected in End Of Central Directory does not correspond to number of entries in Central Directory. exception is thrown at System.IO.Compression.ZipArchive.ReadCentralDirectory() when trying to open the created file again with WordprocessingDocument.
My code looks like this:
using (var fs = new FileStream(fn, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var ms = new MemoryStream())
{
await fs.CopyToAsync(ms);
using (var wordDoc = WordprocessingDocument.Open(ms, true))
{
string docText;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
/*Regex regexText = new Regex("text to replace");
docText = regexText.Replace(docText, "new text");*/
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
await File.WriteAllBytesAsync(target, ms.GetBuffer());
}
using (var wordDoc = WordprocessingDocument.Open(target, true))
{
}
The issue is not repated to the replace itself. Even reading the MainDocumentPart in any way causes this exception to be thrown.
Why the streams? I want to create and modify a document from template and save it afterwards to a stream. But I haven't found any CreateFromTemplate overload neither a Save/SaveAs overload that accepts a stream.

Got a message " MEMORY STREAM IS NOT EXPANDABLE" after using WordprocessingDocument base on Microsoft site on MVC

Currently, I was base on "Search and replace text in a document part (Open XML SDK)" on the Microsoft site. I've realized that the code got an issue after the file has downloaded to my drive.
So I opened that file and got a message
MEMORY STREAM IS NOT EXPANDABLE at sw.Write(docText);
How to fix that?
In GenerateDocxHelper class:
private readonly MemoryStream _mem;
private Dictionary<string, string> _dicData;
public GenerateDocxHelper(string path)
{
_mem = new MemoryStream(System.IO.File.ReadAllBytes(path));
_dicData = new Dictionary<string, string>();
}
public MemoryStream ReplaceTextInWord()
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(_mem, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
foreach (var data in _dicData)
{
docText = docText.Replace(data.Key, data.Value);
}
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
_mem.Seek(0, SeekOrigin.Begin);
return _mem;
}
You should create the MemoryStream with capacity = 0 which means it is resizeable,
and then add the bytes you have read from the file.
var allBytes = File.ReadAllBytes(path);
//this makes _mem resizeable
_mem = new MemoryStream(0);
_mem.Write(allBytes, 0, allBytes.Length);
Check this answer

Exception in saving word document

When I execute the below code to save the word file following exception occurs.please help me to correct the issue.thanks.
Cannot get stream with FileMode.Create, FileMode.CreateNew, FileMode.Truncate, FileMode.Append when access is FileAccess.Read.
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(path, false))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
//Regex regexText = new Regex("<var_Date>");
docText = docText.Replace("<var_Date>", DateTime.Now.ToString("MMM dd,yyyy"));
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
sw.Write(docText);
}
Right here:
WordprocessingDocument.Open(path, false))
The second argument is isEditable, you passed false. So you've opened it as read-only.
Ref: https://msdn.microsoft.com/en-us/library/cc562234.aspx

Return byte array of openxml document

I'm using the following code to generate an openxml document and save it on the server and that works fine, however now i'm trying to generate it to a byte stream to serve out straight away without saving to the server but the document gets corrupted in the process.
Working Code
public static void CreateWordDoc(List<objReplace> lstReplace, String TemplateFile, String OutputPath)
{
File.Delete(OutputPath);
File.Copy(TemplateFile, OutputPath);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(OutputPath, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
docText = sr.ReadToEnd();
foreach (var ro in lstReplace)
{
Regex regexText = new Regex(ro.Find);
docText = regexText.Replace(docText, ro.Replace);
}
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
}
Code that produces currupted XML - that I want to get working
public static byte[] CreateWordDocToStream(List<objReplace> lstReplace, String TemplateFile)
{
string docText = null;
byte[] filebytes = File.ReadAllBytes(TemplateFile);
using (MemoryStream stream = new MemoryStream(filebytes))
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true))
{
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
docText = sr.ReadToEnd();
foreach (var ro in lstReplace)
{
Regex regexText = new Regex(ro.Find);
docText = regexText.Replace(docText, ro.Replace);
}
}
}
return Encoding.ASCII.GetBytes(docText);
}

Search And Replace Text in OPENXML (Added file)

I know there is alot of posts on it, BUT nothing worked for my problem:
Im using OPENxml to create word document, and I am adding some ready files to the document during the creation. I want to change some text in the file that I am adding after the document is ready. So thats what I tried:
First creating the document:
fileName = HttpContext.Current.Server.MapPath("~/reports/"+fileName+".docx");
using (var doc = WordprocessingDocument.Create(
fileName, WordprocessingDocumentType.Document))
{
///add files and content inside the document
addContentFile("template1part1", HttpContext.Current.Server.MapPath("~/templates/template1part1.docx"), mainPart);
}
this is how I am adding the files:
private static void addContentFile(string id,string path, MainDocumentPart mainPart){
string altChunkId = id;
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(
AlternativeFormatImportPartType.WordprocessingML, altChunkId);
using (FileStream fileStream = File.Open(path, FileMode.Open))
{
chunk.FeedData(fileStream);
fileStream.Close();
}
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
mainPart.Document.Body.Append(altChunk);
mainPart.Document.Save();
}
And this is how I am trying to replace text AFTER I created the file (after i finished to use WordprocessingDocument)
First try:
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
docText = sr.ReadToEnd();
docText = new Regex(findText, RegexOptions.IgnoreCase).Replace(docText, replaceText);
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
sw.Write(docText);
}
Second try:
using ( WordprocessingDocument doc =
WordprocessingDocument.Open(#"yourpath\testdocument.docx", true))
{
var body = doc.MainDocumentPart.Document.Body;
var paras = body.Elements<Paragraph>();
foreach (var para in paras)
{
foreach (var run in para.Elements<Run>())
{
foreach (var text in run.Elements<Text>())
{
if (text.Text.Contains("text-to-replace"))
{
text.Text = text.Text.Replace("text-to-replace", "replaced-text");
}
}
}
}
}
}
None of them worked, and I tried much more.
Its worked for text that I am manually add to the document, but its now working for text that I am adding from the ready files.
there is a way to do it?
The way you are adding the files are using altchuncks. But you are trying to replace things as if you are modifying the resulting document's openxml.
When you merge documents as altchuncks you are basically adding them as embedded external files to the original document but not as openxml markup. Which means you cannot treat the additional attached documents as openxml documents.
If you want to achieve what you are trying, you have to merge the documents as explained in my answer here - https://stackoverflow.com/a/18352219/860243 which makes the resulting document a proper openxml document. Which allows you to modify it later as you wish.

Categories

Resources