I'm new to VSTO and OpenXML and I would like to develop some Word add-in. This add-in should use OpenXML, so is it possible to edit opened document?
For example I have opened Word document and I would like to replace some text using OpenXML on button click.
So I have this code.
var fileFullName = Globals.ThisAddIn.Application.ActiveDocument.FullName;
Globals.ThisAddIn.Application.ActiveDocument.Close(WdSaveOptions.wdSaveChanges, WdOriginalFormat.wdOriginalDocumentFormat, true);
//edit document using OpenXml here
Globals.ThisAddIn.Application.Documents.Open(fileFullName);
And i found this to add text to Word using OpenXML
How to: Open and add text to a word processing document (Open XML SDK)
But i can't figure out how to make them work together.
Can anyone help me with this, Thanks
This is how i solved it:
private void button1_Click(object sender, RibbonControlEventArgs e)
{
var fileFullName = Globals.ThisAddIn.Application.ActiveDocument.FullName;
Globals.ThisAddIn.Application.ActiveDocument.Close(WdSaveOptions.wdSaveChanges, WdOriginalFormat.wdOriginalDocumentFormat, true);
OpenAndAddTextToWordDocument(fileFullName, "[USER_NAME]");
Globals.ThisAddIn.Application.Documents.Open(fileFullName);
}
public static void OpenAndAddTextToWordDocument(string filepath, string txt)
{
// Open a WordprocessingDocument for editing using the filepath.
WordprocessingDocument wordprocessingDocument =
WordprocessingDocument.Open(filepath, true);
// Assign a reference to the existing document body.
Body body = wordprocessingDocument.MainDocumentPart.Document.Body;
// Add new text.
DocumentFormat.OpenXml.Wordprocessing.Paragraph para = body.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
Run run = para.AppendChild(new Run());
run.AppendChild(new Text(txt));
// Close the handle explicitly.
wordprocessingDocument.Close();
}
}
You can do something like that;
public static void SearchAndReplace(string document)
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
Regex regexText = new Regex("Hello world!");
docText = regexText.Replace(docText, "Hi Everyone!");
using (StreamWriter sw = new StreamWriter(wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
}
Please read this post for more details.
https://msdn.microsoft.com/en-us/library/office/bb508261.aspx
Related
I have searched a lot for the solution but can't find any.
I have a .docx file inside my MVC project folder which I want to open to overwrite some text but I'm unable to do so.
Inside my project folder, I have a Template folder and in this folder a genrated.docx file that I want to open. Here is my code:
using (WordprocessingDocument doc = WordprocessingDocument.Open
(#"~/Template/genrated.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("to-replace"))
{
text.Text = text.Text.Replace("to-replace", "replace-with");
run.AppendChild(new Break());
}
}
}
}
}
Please help me with this...
Your simplistic approach to replacing text only works in simple cases. Unfortunately, as soon as you use Microsoft Word to edit your template, your text "to-replace" might get split in multiple runs. This then means that you can't find your text "to-replace" if you only look for it in a single Text instance.
The following unit test demonstrates that by creating a document with two paragraphs, one having a single Text instance with your text "to-replace" and another one in which that same text is split into two Run and Text instances.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Xunit;
namespace CodeSnippets.Tests.OpenXml.Wordprocessing
{
public class SimplisticTextReplacementTests
{
private const string ToReplace = "to-replace";
private const string ReplaceWith = "replace-with";
private static MemoryStream CreateWordprocessingDocument()
{
var stream = new MemoryStream();
const WordprocessingDocumentType type = WordprocessingDocumentType.Document;
using WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, type);
MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
mainDocumentPart.Document =
new Document(
new Body(
new Paragraph(
new Run(
new Text(ToReplace))),
new Paragraph(
new Run(
new Text("to-")),
new Run(
new Text("replace")))));
return stream;
}
private static void ReplaceText(MemoryStream stream)
{
using WordprocessingDocument doc = WordprocessingDocument.Open(stream, true);
Body body = doc.MainDocumentPart.Document.Body;
IEnumerable<Paragraph> paras = body.Elements<Paragraph>();
foreach (Paragraph para in paras)
{
foreach (Run run in para.Elements<Run>())
{
foreach (Text text in run.Elements<Text>())
{
if (text.Text.Contains(ToReplace))
{
text.Text = text.Text.Replace(ToReplace, ReplaceWith);
run.AppendChild(new Break());
}
}
}
}
}
[Fact]
public void SimplisticTextReplacementOnlyWorksInSimpleCases()
{
// Arrange.
using MemoryStream stream = CreateWordprocessingDocument();
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, false))
{
Document document = wordDocument.MainDocumentPart.Document;
Paragraph firstParagraph = document.Descendants<Paragraph>().First();
Assert.Equal(ToReplace, firstParagraph.InnerText);
Assert.Contains(firstParagraph.Descendants<Text>(), t => t.Text == ToReplace);
Paragraph lastParagraph = document.Descendants<Paragraph>().Last();
Assert.Equal(ToReplace, lastParagraph.InnerText);
Assert.DoesNotContain(lastParagraph.Descendants<Text>(), t => t.Text == ToReplace);
}
// Act.
ReplaceText(stream);
// Assert.
using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, false))
{
Document document = wordDocument.MainDocumentPart.Document;
Paragraph firstParagraph = document.Descendants<Paragraph>().First();
Assert.Equal(ReplaceWith, firstParagraph.InnerText);
Assert.Contains(firstParagraph.Descendants<Text>(), t => t.Text == ReplaceWith);
Paragraph lastParagraph = document.Descendants<Paragraph>().Last();
Assert.NotEqual(ReplaceWith, lastParagraph.InnerText);
Assert.DoesNotContain(lastParagraph.Descendants<Text>(), t => t.Text == ReplaceWith);
}
}
}
}
Hi I am trying to read through all the CustomXMLParts of some Excel files with the following Code but i cannot figure out how to get the xml Data of each individual part.
I cant seem to find the solution online anywhere
public void getCustomXMLParts(string path){
// Open the document for editing.
int nCount = 0;
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(path, false)){
// Code removed here.
WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
foreach (CustomXmlPart xmlPart in workbookPart.CustomXmlParts)
{
XmlDocument oDoc = new XmlDocument();
//oDoc.Load();
Response.Write("<Textarea cols=200 rows=10>"+ xmlPart.Uri + "</textarea>");
nCount = nCount + 1;
}
}
Response.Write("<BR>XML Parts Count=" + nCount);
}
There is XML Data store in multiple XMLParts and i would just like to read the XML Part into my C# Code.
Thanks.
figured it out, had to use the following:
StreamReader reader = new StreamReader(xmlPart.GetStream(FileMode.Open, FileAccess.Read));
string FullXML = reader.ReadToEnd();
Using C# in VS, I am trying to change the author name in track changes found in a word document header based on their dates. Using the debugger, it seems that the author's name is getting changed, but the document changes are not getting saved. I have included the 'headerPart.Header.Save()' line, which would presumably do trick, but no luck. I need help saving the document after the changes have been made - thanks!
private void changeRevAuthor(string docPath, string input_project_date)
{
using (Stream stream = System.IO.File.Open(docPath, FileMode.OpenOrCreate))
{
stream.Seek(0, SeekOrigin.End);
XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
using (WordprocessingDocument document = WordprocessingDocument.Open(stream, true))
{
foreach (HeaderPart headerPart in document.MainDocumentPart.HeaderParts)
{
foreach (OpenXmlElement headerElement in headerPart.RootElement.Descendants())
{
OpenXmlElement children = headerPart.RootElement;
XElement xchildren = XElement.Parse(children.OuterXml);
var ychildren = xchildren.Descendants().Where(x => x.Attributes(w + "author").Count() > 0);
foreach (XElement descendant in ychildren)
{
var date = descendant.Attribute(w + "date").ToString().Substring(8, 10);
if (DateTime.Parse(date) > DateTime.Parse(input_project_date))
{
descendant.SetAttributeValue(w + "author", "new author name");
Debug.WriteLine("this is the new one" + descendant);
}
}
}
headerPart.Header.Save();
Debug.WriteLine("We got here");
}
document.Close();
}
}
}
Use MainDocumentPart save() method to save the changes in the document.
ie:document.MainDocumentPart.Document.Save();
i am developing a resume archive where people upload their resume and that resume will be saved in a specific location. the most important things is people may use any version of MS-word to prepare their resume and resume file extension could be doc or docx. so i just like to know is there any free library available which i can use to extract text data from doc or docx file which will work in case of all ms-word version and also work if ms-word is not install in pc. i search google and found some article to extract text data from doc file but i am not sure does they work in case of all ms-word version. so please guide me with info that which library i should use to extract data from ms-word irrespective of ms-word version also give me some good article link on this issue.
also guide me is there any viewer available which i can use to show doc file content from my c# apps irrespective of ms-word version.
thanks
i got the answer
**Need to add this reference Microsoft.Office.Interop.Word**
using System.Runtime.InteropServices.ComTypes;
using System.IO;
public static string GetText(string strfilename)
{
string strRetval = "";
System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
if (File.Exists(strfilename))
{
try
{
using (StreamReader sr = File.OpenText(strfilename))
{
string s = "";
while ((s = sr.ReadLine()) != null)
{
strBuilder.AppendLine(s);
}
}
}
catch (Exception ex)
{
SendErrorMail(ex);
}
finally
{
if (System.IO.File.Exists(strfilename))
System.IO.File.Delete(strfilename);
}
}
if (strBuilder.ToString().Trim() != "")
strRetval = strBuilder.ToString();
else
strRetval = "";
return strRetval;
}
public static string SaveAsText(string strfilename)
{
string fileName = "";
object miss = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.Document doc = null;
try
{
Microsoft.Office.Interop.Word.Application wordApp = new Microsoft.Office.Interop.Word.Application();
fileName = Path.GetDirectoryName(strfilename) + #"\" + Path.GetFileNameWithoutExtension(strfilename) + ".txt";
doc = wordApp.Documents.Open(strfilename, false);
doc.SaveAs(fileName, Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDOSText);
}
catch (Exception ex)
{
SendErrorMail(ex);
}
finally
{
if (doc != null)
{
doc.Close(ref miss, ref miss, ref miss);
System.Runtime.InteropServices.Marshal.ReleaseComObject(doc);
doc = null;
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
return fileName;
}
See the following:
http://msdn.microsoft.com/en-us/library/cc974107%28office.12%29.aspx
How can i read .docx file?
Microsoft Interop Word Nuget
string docPath = #"C:\whereEverTheFileIs.doc";
Application app = new Application();
Document doc = app.Documents.Open(docPath);
string words = doc.Content.Text;
doc.Close();
app.Quit();
I am new to C#. How can I write data into one file? This is my code so far:
public void convertHTML(string strData, string strTitle)
{
int position = strTitle.LastIndexOf('.');
strTitle = strTitle.Remove(position);
strTitle= strTitle + ".html";
StreamWriter sw = new StreamWriter(strTitle); //strTitle is FilePath
sw.WriteLine("<html>");
sw.WriteLine("<head><title>{0}</title></head>",strTitle);
//MessageBox.Show("this editor");
sw.WriteLine("<body>");
sw.WriteLine(strData); //strData is having set of lines
sw.WriteLine("</body>");
sw.WriteLine("</html>");//*/
lstHtmlFile.Items.Add(strTitle);
}
it will simply create one blank html file it won't have any data
You need to flush and close the StreamWriter:
using (StreamWriter sw = new StreamWriter(strTitle))
{
sw.WriteLine("<html>");
sw.WriteLine("<head><title>{0}</title></head>",strTitle);
sw.WriteLine("<body>");
sw.WriteLine(strData);
sw.WriteLine("</body>");
sw.WriteLine("</html>");
}
Using using does the trick.
You can add block using in order to clean your non managed object
using (var streamWriter = new StreamWriter(strTitle))
{
....
}
Link : http://msdn.microsoft.com/fr-fr/library/vstudio/yh598w02.aspx