Solved

OpenXML Iterate and Replace

Posted on 2011-03-24
3
3,591 Views
Last Modified: 2012-05-11
How do you iterate through all the content controls?  I have a document with several RichText content controls but the process is not finding all the content controls within the document.  It appears that it is only finding content controls that are on the root and not ones that are within the body text.

Also, once I find a content control how do I replace the text?

This should be easy right?

public static void MyMethod(string docfile)
        {
            using (WordprocessingDocument doc = WordprocessingDocument.Open(docfile, true))
            {
                var docPart = doc.MainDocumentPart;
                // Find the first content control whose Alias property matches the supplied name.
                var sdts = docPart.Document.Descendants<SdtBlock>();
                foreach (var sdt in sdts)
                {
                    //todo it is not finding all content controls, it appeas they can't be with the body text
                    if (sdt.SdtContentBlock.InnerText == "ReplaceMeText")
                    {
                        //todo how to replace text: sdt.SdtContentBlock.InnerText = "MyNewText";

                        System.Diagnostics.Debug.WriteLine("Found" + sdt.SdtContentBlock.InnerText);
                    }

                }
            }
        }

Open in new window

0
Comment
Question by:tampsystems
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
3 Comments
 
LVL 1

Expert Comment

by:nulliusinverba
ID: 35212916
I had this problem too.

I found that some of the content controls were of type "StdBlock", but some others were of type "SdtRun".

Best thing to do it is to firstly check out the Open XML SDK Productivity Tool, which opens your document and reflects the code.  Then you can drill down to where you know the controls are and see what type of element they are.

I also made myself a little console app that analyses a file and tells me how many blocks and runs there are, and what their control name is.  It's real simple.  THere's probably much better ways to do this, but I'm new to this too, and it works for me.  Here's my analysis program:

 
class Program
    {
        static void Main(string[] args)
        {
            // (1) Objects used throughout
            string fileName = @"C:\...\Letter.dotx"; // file to open
            int hb = 0; // for count of StdBlocks in header
            int hr = 0; // for count of SrdRuns in header
            int bb = 0; // for count of StdBlocks in body
            int br = 0; // for count of StdRuns in body
            List<string> hBlocks = new List<string>(); // to hold list of aliases of all blocks in header
            List<string> hRuns = new List<string>(); // to hold list of aliases of all runs in header
            List<string> bBlocks = new List<string>(); // to hold list of aliases of all blocks in body
            List<string> bRuns = new List<string>(); // to hold list of aliases of all runs in body

            // (2) Create the memory stream
            byte[] templateBytes = System.IO.File.ReadAllBytes(fileName);
            using (MemoryStream templateStream = new MemoryStream())
            {
                templateStream.Write(templateBytes, 0, (int)templateBytes.Length);

                // (3) Open the template as a wordprocessing document
                using (WordprocessingDocument outDoc = WordprocessingDocument.Open(templateStream, true))
                {
                    MainDocumentPart mainPart = outDoc.MainDocumentPart;

                    // (4) Analyse the header parts, count the number of runs and blocks, and write the string names to the relevant list
                    var hp = mainPart.HeaderParts;
                    foreach (var hd in hp)
                    {
                        foreach (SdtElement sdt in hd.Header.Descendants<SdtElement>().ToList())
                        {
                            string type = sdt.GetType().Name;
                            SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();
                            string sdtTitle = alias.Val.Value;
                            if (alias != null)
                            {
                                if (type == "SdtBlock")
                                {
                                    hb++;
                                    hBlocks.Add(sdtTitle);
                                }
                                else if (type == "SdtRun")
                                {
                                    hr++;
                                    hRuns.Add(sdtTitle);
                                }
                            }
                        }
                    }

                    // (5) Analyse the body parts, count the number of runs and blocks, and write the string names to the relevant list
                    foreach (SdtElement sdt in mainPart.Document.Descendants<SdtElement>().ToList())
                    {
                        string type = sdt.GetType().Name;
                        SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();
                        string sdtTitle = alias.Val.Value;

                        if (alias != null)
                        {
                            if (type == "SdtBlock")
                            {
                                bb++;
                                bBlocks.Add(sdtTitle);
                            }
                            else if (type == "SdtRun")
                            {
                                br++;
                                bRuns.Add(sdtTitle);
                            }
                        }
                    }
                                     
                }

            }

            // (6) Write the results of the analysis to the Console
            Console.WriteLine("The header part contains the following.\n\r\t{0} elements are StdRun:", hr.ToString());
            foreach (string x in hRuns)
            {
                Console.WriteLine("\t\t{0}", x);
            }
            Console.WriteLine("\t{0} elements are StdBlock:", hb.ToString());
            foreach (string x in hBlocks)
            {
                Console.WriteLine("\t\t{0}", x);
            }
            Console.WriteLine("\n\rThe body part contains the following.\n\r\t{0} elements are StdRun:", br.ToString());
            foreach (string x in bRuns)
            {
                Console.WriteLine("\t\t{0}", x);
            }
            Console.WriteLine("\t{0} elements are StdBlock:", bb.ToString());
            foreach (string x in bBlocks)
            {
                Console.WriteLine("\t\t{0}", x);
            }
        }
    }

Open in new window


Hope this helps.

Cheers,

Tim.
0
 

Author Comment

by:tampsystems
ID: 35216581
I tried your code but it appears that all of the SdtAlias were null.
                       
SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();

if (alias != null) //always null
0
 
LVL 1

Accepted Solution

by:
nulliusinverba earned 500 total points
ID: 35363182
Sorry mate - wish that had worked for you.

So what's going on is going to be a function of the (your) Word document which is being analysed by the code.

Best you could do is use the productivity tool to drill down to your content controls and see where they fit into the heirarchy of StdElement, SdtBlock, SdtRun, etc...

The productivity tool really is your best friend.
0

Featured Post

MS Dynamics Made Instantly Simpler

Make Your Microsoft Dynamics Investment Count  & Drastically Decrease Training Time by Providing Intuitive Step-By-Step WalkThru Tutorials.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
This is a high-level webinar that covers the history of enterprise open source database use. It addresses both the advantages companies see in using open source database technologies, as well as the fears and reservations they might have. In this…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…

688 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question