wordpress hit counter
Search and Replace Text in an Open XML WordprocessingML Document - OpenXML Developer - Blog - OpenXML Developer
Goodbye and Hello

OpenXmlDeveloper.org is Shutting Down

There is a time for all good things to come to an end, and the time has come to shut down OpenXmlDeveloper.org.

Screen-casts and blog posts: Content on OpenXmlDeveloper.org will be moving to EricWhite.com.

Forums: We are moving the forums to EricWhite.com and StackOverflow.com. Please do not post in the forums on OpenXmlDeveloper.org. Instead, please post in the forums at EricWhite.com or at StackOverflow.com.

Please see this blog post for more information about my plans moving forward.  Cheers, Eric

Search and Replace Text in an Open XML WordprocessingML Document

Search and Replace Text in an Open XML WordprocessingML Document

Rate This
  • Comments 20

This page has been moved.  You can find this content at the following link: Search and Replace Text in an Open XML WordprocessingML Document

OpenXmlDeveloper.org is shutting down as an active site.  See this blog post at EricWhite.com for more information.

Attachment: SearchAndReplace.zip
  • Thanks Eric this article was very helpful.  I've been testing with your sample code and strings with certain characters in them seem to cause a problem.
    For example, the following line in code

    OpenXmlPowerTools.SearchAndReplacer.SearchAndReplace(wordDoc, "POSITION HERE", "DYNAMIC CONTENT PLACED HERE", false);

    works and find and replaces the string POSITION HERE in the document with DYNAMIC CONTENT PLACED HERE.

    However if I change the code to try this line (see double !! at start and end of string) it doesn't find and replace the text !!POSITION HERE!!

    OpenXmlPowerTools.SearchAndReplacer.SearchAndReplace(wordDoc, "!!POSITION HERE!!", "DYNAMIC CONTENT PLACED HERE", false);

    I'm trying to use the code to dynamically populate a template with data values from another source and want to 'mark' the places in the document which need to be replaced by using string patterns like !!replace this!! or **replace this** but am having difficulty.

    Is there something simple I am missing?   Thanks for your help
  • Hi Mort,

    I'm a bit embarrassed - you found a bug in the code.  The code would not find the string to replace if the search string matched the string that was at the very end of the paragraph.  Line 115 should read:

    for (int i = 0; i <= runs.Count - search.Length; ++i)

    The incorrect version was:

    for (int i = 0; i < runs.Count - search.Length; ++i)

    I've updated the code in the zip file.  Sorry about that.

  • Thanks Eric!  Works great now
  • Hi again Eric, I have one other questions about the search and replace code.  I have found that it does not work if the text to be replaced is inside of a Text Box.  I have tried stepping through the code to work out why but have been unsuccessful.  Do you know why this would be?

  • Hi Mort, You are right - the algorithm neglected to process descendant paragraphs of a paragraph.  I've updated the code.  It now works properly.


  • Thanks again Eric.  It works for me now.  This SearchAndReplace class has been invaluable to a project I'm working on.  I'm in the transition from Lotus Notes developer to Sharepoint developer and resources like this website have made things alot easier.

  • Hi Eric,

    I've been having a play with the code sample, and noticed that it doesn't seem to correctly replace instances of the search string in a document after they're used in a text box. So if, for example, I have the following document:

    hello world

    [text box] hello world [/text box]

    hello world

    ...and am replacing the string 'hello' with 'hi', the result I get is...

    hi world

    [text box] hi world [/text box]

    hello world

    I'm pretty sure this is not the intended behaviour! Otherwise it's a very helpful article, thanks :)


  • Hi Zaxian,

    I am not seeing the symptoms you mention, but I am sure that it is due to me not creating the document properly.  Would you kindly send me a sample document where text is not being replaced properly?  You can either post it here on the forum, or send it as a message on OpenXMLDeveloper.org, or send to my email eric at ericwhite.com.


  • Recently I wrote some code that implemented search-and-replace for Open XML WordprocessingML documents

  • Hi Eric,

    First of all Thank you very much for providing the very usefull knowledge and code for office automation using OpenXML.

    I am Sanjeev, just started using OpenXml for editing the office document. I found your very usefull article and code to search and replace the text in word files. It is very good and very usefull for me to complete the tasks. Thank you for that.

    I am using Search and replace functionality by placing some place holders in the documents. I succeeded to replace the place holders, but only thing I am not able do is to replace the place holders with the text having multiple lines.

    I tried by adding "W:br" node in the XmlElement, but still it is not giving the text on next line.

    Am i missing some thing? Please help ......

    Thanks in advance.

    Thanks and Regards,


  • Hi Eric

     First of all thank for the search and replace code, but the problem is that I can not make it work for my example.

    here's the sample document.xml:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>

    <w:document xmlns:ve="schemas.openxmlformats.org/.../2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="schemas.openxmlformats.org/.../relationships" xmlns:m="schemas.openxmlformats.org/.../math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp="schemas.openxmlformats.org/.../wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="schemas.openxmlformats.org/.../main" xmlns:wne="schemas.microsoft.com/.../wordml"><w:body><w:p w:rsidR="009001B7" w:rsidRDefault="009001B7" w:rsidP="009001B7"><w:pPr><w:pStyle w:val="Heading1"/><w:rPr><w:lang w:val="en-CA"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>The first testing form</w:t></w:r></w:p><w:p w:rsidR="009001B7" w:rsidRDefault="009001B7" w:rsidP="009001B7"><w:pPr><w:rPr><w:lang w:val="en-CA"/></w:rPr></w:pPr></w:p><w:p w:rsidR="005404F9" w:rsidRDefault="009001B7" w:rsidP="009001B7"><w:pPr><w:rPr><w:lang w:val="en-CA"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>This is a test</w:t></w:r><w:r w:rsidR="005404F9"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>ing document for data field1</w:t></w:r><w:proofErr w:type="gramStart"/><w:r w:rsidR="005404F9"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>: !!</w:t></w:r><w:proofErr w:type="gramEnd"/><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t xml:space="preserve">Plan </w:t></w:r><w:proofErr w:type="spellStart"/><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>Member.First</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t xml:space="preserve"> Name</w:t></w:r><w:r w:rsidR="005404F9"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>!!</w:t></w:r></w:p><w:p w:rsidR="009001B7" w:rsidRDefault="005404F9" w:rsidP="009001B7"><w:pPr><w:rPr><w:lang w:val="en-CA"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t xml:space="preserve"> </w:t></w:r><w:proofErr w:type="spellStart"/><w:r w:rsidR="009001B7"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>Datafile</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r w:rsidR="009001B7"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t xml:space="preserve"> 2</w:t></w:r><w:proofErr w:type="gramStart"/><w:r w:rsidR="009001B7"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t xml:space="preserve">: </w:t></w:r><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>!!</w:t></w:r><w:proofErr w:type="gramEnd"/><w:r w:rsidR="009001B7"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t xml:space="preserve">Plan </w:t></w:r><w:proofErr w:type="spellStart"/><w:r w:rsidR="009001B7"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>Member.Last</w:t></w:r><w:proofErr w:type="spellEnd"/><w:r w:rsidR="009001B7"><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t xml:space="preserve"> Name</w:t></w:r><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>!!</w:t></w:r></w:p><w:p w:rsidR="009001B7" w:rsidRDefault="009001B7" w:rsidP="009001B7"><w:pPr><w:rPr><w:lang w:val="en-CA"/></w:rPr></w:pPr></w:p><w:p w:rsidR="009001B7" w:rsidRDefault="009001B7" w:rsidP="009001B7"><w:pPr><w:rPr><w:lang w:val="en-CA"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-CA"/></w:rPr><w:t>End of testing Document.</w:t></w:r></w:p><w:p w:rsidR="009001B7" w:rsidRDefault="009001B7" w:rsidP="009001B7"><w:pPr><w:rPr><w:lang w:val="en-CA"/></w:rPr></w:pPr></w:p><w:p w:rsidR="00924DD5" w:rsidRDefault="00924DD5"/><w:sectPr w:rsidR="00924DD5" w:rsidSect="00924DD5"><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/><w:cols w:space="708"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w:document>

    SearchAndReplacer.SearchAndReplace(TargetForm, "!!Plan Member.First Name!!","Frank");

    Can you please let me know what the problem is?



  • Sanjeev, I encountered a similar problem trying to insert a <w:br /> in between lines of text.  My approach was not as elegant as yours since I was just adding the "<w:br />" string at the end of the text as I built the multiple lines.  Through my debugging, I found that the SearchAndReplace was converting the "<" and ">" to "<" and ">" and I couldn't figure out how to prevent it.  What I ended up doing was using a Regex.Replace to put back the "<" and ">" characters.  Probably not the best way of doing things, but I had to get it working.  Perhaps Eric or someone else here can provide a better solution.

  • Hi eric, can you please point the differences between this version of the code and the one that ignored the textboxes? I need to ignore textboxes in searches.



  • Hi Eric,

    Thanks for the article I have successfuly used your code in my app.

    I have come across a bug when replacing the text with an empty string.

    At line 149 "if (replace[0] == ' ' || replace[replace.Length - 1] == ' ')" an index out of bounds exception is rasied.

    I fixed this by wrapping the above inside if (replace.Length > 0) {...}

    Mike Williams

  • Hi Eric,

    Correction to earlier post

    I have now changed the wrapping code to if (!string.IsNullOrEmpty(replace)) {...} to hanlde null strings as well as empty strings.


    Mike Williams

Page 1 of 2 (20 items) 12