How to replace text in Word document using Openxml - c#

I have a simple word document with only a single word "$Hello$". I'm trying to change "$Hello$" to "Goodbye" but nothing happens and there's no errors. How can I get the code working? "$Hello$" is in a paragraph.
using System;
using System.IO;
using System.Text.RegularExpressions;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace OpenXMLTests
{
class Program
{
static void Main(string[] args)
{
String document = "TestDoc.docx";
using (WordprocessingDocument doc = WordprocessingDocument.Open(document, true))
{
Body body = doc.MainDocumentPart.Document.Body;
foreach (Table t in body.Descendants<Table>())
{
String tableName = t.GetFirstChild<TableProperties>().TableCaption.Val;
Console.WriteLine(tableName);
}
string docText = null;
using (StreamReader sr = new StreamReader(doc.MainDocumentPart.GetStream())) //Reads file to string
{
docText = sr.ReadToEnd();
}
docText = docText.Replace("$Hello$", "Goodbye");
using (StreamWriter sw = new StreamWriter(doc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
}
}
}
When I remove this table loop the code works. Not sure whats conflicting
Body body = doc.MainDocumentPart.Document.Body;
foreach (Table t in body.Descendants<Table>())
{
String tableName = t.GetFirstChild<TableProperties>().TableCaption.Val;
Console.WriteLine(tableName);
}

Try to disable AutoSave option.
using (WordprocessingDocument doc =
WordprocessingDocument.Open(document, true, new OpenSettings { AutoSave = false }))
{
...
}
Looks like when AutoSave is enabled and getter of doc.MainDocumentPart.Document.Body is called it causes that doc.MainDocumentPart is not saved properly or it's overriden with original document part.

Related

Microsoft.Office.Word.Interop 2nd Document keeps opening as read-only

Here is my code so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Office.Interop.Word;
using Word = Microsoft.Office.Interop.Word;
namespace WordIterator
{
class LoadDocument
{
public static Document Default()
{
try
{
return AnyDoc(Filepath.Full());
}
catch
{
throw new Exception("Error loading default document.");
}
}
public static Document AnyDoc(string filepath)
{
try
{
object fileName = filepath;
Application wordApp = new Application { Visible = true };
Document aDoc = wordApp.Documents.Open(ref fileName, ReadOnly: false, Visible: true);
aDoc.Activate();
return (aDoc);
}
catch
{
throw new Exception("Error loading document " + filepath + "!");
}
}
}
}
//Main class
namespace WordIterator
{
class Program
{
static void Main(string[] args)
{
Document doc = LoadDocument.Default();
doc.SaveAs2(Filepath.Full().Replace(".docx", "_2.docx"));
Document doc2 =
LoadDocument.AnyDoc(#"C:\Users\netha\Documents\FSharpTest\FTEST\ftestdoc3_2.docx");
What i'm trying to do:
Open a word document(do some stuff with it)
Save it as _2.docx
Then open _2.docx(do some stuff with it)
However the second document keeps opening as read-only, I have it set as read-only false and I've even restarted my computer to make sure it shouldn't be read-only.
Does anyone know why this is opening as Read-Only?
Thank you for any assistance
It is opening as read-only as you do SaveAs "_2.docx" and then you are trying to open the save document again. I would recommend you to close the active tab and then open the document.
You could use the following code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Office.Interop.Word;
using Word = Microsoft.Office.Interop.Word;
using System.IO;
namespace WordIterator
{
class Program
{
static void Main(string[] args)
{
string FilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Test.docx");
Document doc = null;
Application wordApp1 =new Application();
Application wordApp2 = new Application();
string FilePath2 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Test_2.docx");
try
{
object fileName = FilePath;
object fileName2 = FilePath2;
wordApp1 = new Application { Visible = true };
doc = wordApp1.Documents.Open(ref fileName, ReadOnly: false, Visible: true);
doc.SaveAs2(FilePath.Replace(".docx", "_2.docx"));
doc.Close();
Document doc2 = wordApp1.Documents.Open(ref fileName2, ReadOnly: false, Visible: true);
}
catch (Exception ex)
{
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApp1);
}
}
}
}

Read and write to text file efficiently

I have a homework assignment to create a C# console program. It should create a text file with 2 phrases:
Hello, World!
Goodbye, Cruel World!
Then I also must create a program to read the 2 phrases from the file.
After two hours this is what I have. It works, but I want to rewrite the program to be more efficient. I am mainly struggling on how to output the file into a .cs file capable of running.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
//structure.txt contains the program we will enter our values into.
String filePath = "Structure.txt";
WriteToFile(filePath);
}
public static void WriteToFile(string filePath)
{
//create a string array to gather our text file information.
StreamReader reader = new StreamReader(filePath);
StreamReader info = new StreamReader("Structure.txt");
StreamWriter writer = new StreamWriter("Hello.cs", true);
String temp = String.Empty;
while (!info.EndOfStream)
{
String tempstring = String.Empty;
tempstring = reader.ReadLine();
while (!reader.EndOfStream)
{
temp = reader.ReadLine();
writer.WriteLine(temp);
if (temp == "//break")
{
writer.WriteLine("String1 = {}", tempstring);
}
}
}
reader.Close();
info.Close();
writer.Close();
}
}
}
More efficient? sure
// write
string[] lines = new [] {"Hello, World!", "Goodbye, Cruel World!"};
File.WriteAllLines("c:\\myFile.txt", lines);
// read
string[] lines = File.ReadAllLines("c:\\myFile.txt");
This is all. . .

C# : Editing/saving/Sending a docx document

Been strugling with a lot of problems. Using OpenXML on a ASP.NET Core server, I want to create a new docx document based on a template one. Once this document is fully saved, I want it to be sent to my client so he can download it directly. Here's my code :
public IActionResult Post([FromBody] Consultant consultant)
{
using (Stream templateStream = new MemoryStream(Properties.Resources.templateDossierTech))
using (WordprocessingDocument template =
WordprocessingDocument.Open(templateStream, false))
{
string fileName = environment.WebRootPath + #"\Resources\"+ consultant.FirstName + "_" + consultant.LastName + ".docx";
WordprocessingDocument dossierTechniqueDocument =
WordprocessingDocument.Create(fileName,
WordprocessingDocumentType.Document);
foreach (var part in template.Parts)
{
dossierTechniqueDocument.AddPart(part.OpenXmlPart, part.RelationshipId);
}
var body = dossierTechniqueDocument.MainDocumentPart.Document.Body;
var paras = body.Elements();
foreach (var para in paras)
{
foreach (var run in para.Elements())
{
foreach (var text in run.Elements())
{
if (text.InnerText.Contains("{{prenom}}"))
{
var t = new Text(text.InnerText.Replace("{{prenom}}", consultant.FirstName));
run.RemoveAllChildren<Text>();
run.AppendChild(t);
}
}
}
}
dossierTechniqueDocument.MainDocumentPart.Document.Save();
dossierTechniqueDocument.Close();
var cd = new System.Net.Mime.ContentDisposition
{
FileName = consultant.FirstName + "_" + consultant.LastName + ".docx",
Inline = true
};
Response.Headers.Add("Content-Disposition", cd.ToString());
Response.Headers.Add("X-Content-Type-Options", "nosniff");
return File(System.IO.File.ReadAllBytes(fileName),"application/vnd.openxmlformats-officedocument.wordprocessingml.document","Dossier Technique");
}
}
As a first look, it looks like is saving well but when I try to open it on word, it says that it is corrupted for some reason.
That's the same problem when I try to send it. Once it's sent my client doesn't download it (Ajax query).
Do anyone of you have any idea how to fix it ?
Here is the function which creates a document from a template:
static void GenerateDocumentFromTemplate(string inputPath, string outputPath)
{
MemoryStream documentStream;
using (Stream stream = File.OpenRead(inputPath))
{
documentStream = new MemoryStream((int)stream.Length);
CopyStream(stream, documentStream);
documentStream.Position = 0L;
}
using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true))
{
template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
MainDocumentPart mainPart = template.MainDocumentPart;
mainPart.DocumentSettingsPart.AddExternalRelationship("http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate",
new Uri(inputPath, UriKind.Absolute));
mainPart.Document.Save();
}
File.WriteAllBytes(outputPath, documentStream.ToArray());
}

C# Delete line from .txt extension with a changing filename

I am currently trying to make an .exe in c# that I can drag and drop a .txt file onto to remove lines of text that contain the keywords "CM" and/or "Filling". It must be able to overwrite the existing data so there are no new files created. The filename is different every time except for the extension. The data is tab delimited if that has any bearing. I'm aware that there are similar questions to this but I haven't managed to adapt them to suit my needs. Also, I'm very new to this and I've been trying for about a week with no luck.
if (args.Length == 0)
return; // return if no file was dragged onto exe
string text = File.ReadAllText("*.txt");
text = text.Replace("cm", "");
string path = Path.GetDirectoryName(args[0])
+ Path.DirectorySeparatorChar
+ Path.GetFileNameWithoutExtension(args[0])
+ "_unwrapped" + Path.GetExtension(args[0]);
File.WriteAllText("*.txt", text);
\\attempt 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Text.RegularExpressions;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
string concrete = "CM";
string line;
using (StreamReader reader = new StreamReader(#"C:\\Users\drocc_000\Desktop\1611AN24T99-041805221704.txt"))
{
using (StreamWriter writer = new StreamWriter(#"C:\\Users\drocc_000\Desktop\1611AN24T99-041805221704NEW.txt"))
{
while ((line = reader.ReadLine()) != null)
{
// if (String.Compare(line, yourName) == 0)
// continue;
writer.WriteLine(line.Replace(concrete, ""));
}
}
}
\\attempt 2
Thanks for your time.
Regards,
Danny
You can create a console application with the code below and then drag and drop your text file into the .exe file without opening it.
class Program
{
static void Main(string[] args)
{
if (args.Length > 0 && File.Exists(args[0]))
{
string path = args[0];
EditFile(new List<string>() { "CM", "Filling" }, path);
}
Console.Read();
}
public static void EditFile(List<string> keyWords, string filename)
{
List<string> lines = new List<string>();
using (StreamReader sr = new StreamReader(filename))
{
while (sr.Peek() >= 0)
{
lines.Add(sr.ReadLine());
}
sr.Close();
}
int removedLinesCount = 0;
bool writeline;
using (StreamWriter sw = new StreamWriter(filename))
{
foreach (var line in lines)
{
writeline = true;
foreach (var str in keyWords)
{
if (line.Contains(str))
{
writeline = false;
removedLinesCount++;
break;
}
}
if (writeline)
sw.WriteLine(line);
}
Console.WriteLine(removedLinesCount + " lines removed from the file " + filename);
sw.Close();
}
}
}
Something like this?
using System;
using System.IO;
using System.Linq;
namespace ConsoleApp1
{
internal static class Program
{
private static void Main(string[] args)
{
try
{
// Get the filename from the applications arguments
string filename = args[0];
// Read in all lines in the file.
var linesInFile = File.ReadLines(filename);
// Filter out the lines we don't need.
var linesToKeep = linesInFile.Where(line => !line.Contains("CM") && !line.Contains("Filling")).ToArray();
// Overwrite the file.
File.WriteAllLines(filename, linesToKeep);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}

Using regex to delete text based on first line of word docx

Hi I'm currently trying to format a word document whereby based on the word present in the first line a certain paragraph is kept. Example:
We refer to above (PST\Non-PST) for your notice
Paragraph 1
Paragraph 2
Paragraph 3
If the word PST is in the first line => keep paragraph 1 and delete paragraph 2 and 3.
If it's Non-PST keep paragraph 2 and delete 1 and 3
this is as far as i have managed to get
using System.IO;
using System.Text.RegularExpressions;
using DocumentFormat.OpenXml.Packaging;
namespace DataToPDF
{
public class Replace_Text
{
public static void SearchAndReplace()
{
string document = #"C:\Users\kishlay02\Desktop\sample.docx";
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
if{
Regex regexText = new Regex("conclude");
docText = regexText.Matches("PST")
}
//Regex regexText1 = new Regex("conclude");
//docText = regexText1.Replace(docText, "", 2);
//Regex regexText2 = new Regex("conclude");
//docText = regexText2.Replace(docText, "closer", 3);
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
}
}
}

Categories