wordpress hit counter
Iterating through all Content Controls in an Open XML WordprocessingML Document - OpenXML Developer - Blog - OpenXML Developer

Iterating through all Content Controls in an Open XML WordprocessingML Document

Blog

Samples, Demos, and Reference Articles

Iterating through all Content Controls in an Open XML WordprocessingML Document

Rate This
  • Comments 9
Sometimes you want to iterate over all content controls in a WordprocessingML document. You may want to search for a content control with a specific tag, or you may want to process all content controls of a specific type. This blog post shows how to iterate over all content controls.

One key point is that if you want to be thorough about this, you need to search for content controls in all parts where content controls can exist. They can exist in the following parts:

  • Main document part
  • Header parts (there can be more than one header part)
  • Footer parts (there can be more than one footer part)
  • End note part (there can be zero or one end note part)
  • Foot note part (there can be zero or one foot note part)
The best way to proceed is to write a method that returns a collection of all content controls for a given part, and then write another method that returns a collection of all content controls for all parts. The most expressive way to write these methods is to write them as extension methods. This allows us to use those methods by simply ‘dotting’ into the extension method. Following is an example that includes the two extension methods, as well as a bit of code to exercise them.

I’ve attached an example document to this post that includes content controls in the main document part, in a header, in a footer, in an end note, and in a foot note.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

public static class ContentControlExtensions
{
    public static IEnumerable<OpenXmlElement> ContentControls(
        this OpenXmlPart part)
    {
        return part.RootElement
            .Descendants()
            .Where(e => e is SdtBlock || e is SdtRun);
    }

    public static IEnumerable<OpenXmlElement> ContentControls(
        this WordprocessingDocument doc)
    {
        foreach (var cc in doc.MainDocumentPart.ContentControls())
            yield return cc;
        foreach (var header in doc.MainDocumentPart.HeaderParts)
            foreach (var cc in header.ContentControls())
                yield return cc;
        foreach (var footer in doc.MainDocumentPart.FooterParts)
            foreach (var cc in footer.ContentControls())
                yield return cc;
        if (doc.MainDocumentPart.FootnotesPart != null)
            foreach (var cc in doc.MainDocumentPart.FootnotesPart.ContentControls())
                yield return cc;
        if (doc.MainDocumentPart.EndnotesPart != null)
            foreach (var cc in doc.MainDocumentPart.EndnotesPart.ContentControls())
                yield return cc;
    }
}

class Program
{
    static void Main(string[] args)
    {
        using (WordprocessingDocument doc =
            WordprocessingDocument.Open("Test.docx", false))
        {
            foreach (var cc in doc.ContentControls())
            {
                SdtProperties props = cc.Elements<SdtProperties>().FirstOrDefault();
                Tag tag = props.Elements<Tag>().FirstOrDefault();
                Console.WriteLine(tag.Val);
            }
        }
    }
}
Attachment: Test.docx
  • hello, I had to add an extra line to check whether the tag variable is null or not before the Console.WriteLine() otherwise I would be getting a null reference exception. thanks

  • If the contentcontrol sits inside a SdtCell, the above method might not be able to find it.

  • I added the SdtCell into this:

           public static IEnumerable<OpenXmlElement> ContentControls(

               this OpenXmlPart part)

           {

               return part.RootElement

                   .Descendants()

                   .Where(e => e is SdtBlock || e is SdtRun || e is SdtCell);

           }

  • Thanks a lot for your post. I tried to run this sample code, but i am getting the following error and not able to proceed.

    "'DocumentFormat.OpenXml.Packaging.OpenXmlPart.RootElement' is inaccessible due to its protection level". I just copied the code and try to run. I have added the reference to the corresponding DLL. Please guide me.

  • This is exactly what I need, however, I will need to go further and take values from a web form and edit the content control tags with the corresponding values. Thanks!

  • Hi Eric, you code works well for the attached docx file, but it doesn't Iterating through all Content Controls if one Content Control contains other Content Control.

    I mean lets say, i have Rich Text Content Control with table inside & inside this table i have lets say CheckBox  Content Control column for all the rows. These checkBox Content Control are not  Iterate through.

    It doesn't read the nested Content Controls.

    Please help in this.

    Thanks

    Gill

  • Hi I am able to find the solution as

    I added the SdtCell into this:

          public static IEnumerable<OpenXmlElement> ContentControls(this OpenXmlPart part)

          {

              return part.RootElement.Descendants().Where(e => e is SdtBlock || e is SdtRun || e is SdtCell);

          }

    Thanks

    Gill

  • In case Some One need the same functionality in VB.Net (as we don't have  yield return in VB.NET)

    <System.Runtime.CompilerServices.Extension()> _

       Public Function getDocumentContentControls(doc As WordprocessingDocument)

           Dim lstElements As New List(Of OpenXmlElement)

           For Each ContentControl As OpenXmlElement In GetPartContentControls(doc.MainDocumentPart)

               lstElements.Add(ContentControl)

           Next

           For Each header As OpenXmlPart In doc.MainDocumentPart.HeaderParts

               For Each ContentControl As OpenXmlElement In GetPartContentControls(header)

                   lstElements.Add(ContentControl)

               Next

           Next

           For Each footer As OpenXmlPart In doc.MainDocumentPart.FooterParts

               For Each ContentControl As OpenXmlElement In GetPartContentControls(footer)

                   lstElements.Add(ContentControl)

               Next

           Next

           If doc.MainDocumentPart.FootnotesPart IsNot Nothing Then

               Dim lobjFootNotes As OpenXmlPart = doc.MainDocumentPart.FootnotesPart

               For Each ContentControl As OpenXmlElement In GetPartContentControls(lobjFootNotes)

                   lstElements.Add(ContentControl)

               Next

           End If

           If doc.MainDocumentPart.EndnotesPart IsNot Nothing Then

               Dim lobjEndNotes As OpenXmlPart = doc.MainDocumentPart.EndnotesPart

               For Each ContentControl As OpenXmlElement In GetPartContentControls(lobjEndNotes)

                   lstElements.Add(ContentControl)

               Next

           End If

           Return lstElements

       End Function

    Thanks

    Gill

  • gsgill76 can you post the whole vb code for me please? You are referencing a method called GetPartContentControls and not too sure what that is doing in your code.

Page 1 of 1 (9 items)