wordpress hit counter
How to insert a Word table into a content control? - .Net - Development Tools - OpenXML Developer

How to insert a Word table into a content control?

Development Tools

Discussions about working with Open XML using a wide range of development tools

How to insert a Word table into a content control?

  • rated by 0 users
  • This post has 6 Replies |
  • 4 Followers
  • I need to dynamically generate a Word 2007 table from data from a SQL Server database and place it into a named content control. 

    After I've located the named content control, I need to retrieve the data inside the control.  It will have a list of "Id's".  These will be Id's for database record that my application will need to query to create the table.

    I have been able to initially create a table from a data source and place it into a Word document, but I have a sinking feeling my solution isn't the most optimal way of handling this task.

    Be aware that there are many named content controls in the document and many tables need to be generated and placed into those controls, but each table will have a different structure and set of data.  So I need to place the correct table into the correct content control.

    This will need to be reused across many Word documents, each having a slightly different responsibility for it's data.

    Here's some code I've already written to find a named content control.  While I can find the control, I also need to read the data inside the control.  I got this to work but it doesn't seem like the most efficient way of searching for a content control and getting it's data.

     

    public static void FindContentControl(string fileName, string controlName)
    {
        using (WordprocessingDocument wordDoc = 
        	WordprocessingDocument.Open(fileName, false))
        {
    	var mainPart = wordDoc.MainDocumentPart;
    	var contentParts = mainPart.Document.Body.Descendants<SdtBlock>();
    	foreach (var item in contentParts)
    	{
    	    var node = item.Descendants<SdtAlias>().FirstOrDefault();
    	    if (node.Val == controlName)
    	    {
    		Console.WriteLine(node.Val);
    		var contentBlock = item.Descendants<SdtContentBlock>().FirstOrDefault();
    		var paragraph = contentBlock.Descendants<Paragraph>().FirstOrDefault();
    		var run = paragraph.Descendants<Run>().FirstOrDefault();
    		var text = run.InnerText;
    		Console.WriteLine("    {0}", text);
    	    }
    
    	}                    
        }
    }

     

    This is my working code that can drop a table into a Word document, but it just appends it to the document, it doesn't place it in any particular location.

     

    public static void CreateTableWithBuilder(string fileName)
    {
        var dataSource = new data.CoreReferenceDataSource();
    
        TableBuilder.TableBuilder builder = new CoreReferenceTable(dataSource.GetAll());
        TableDirector director = new TableDirector();
        director.SetTable(builder);
        director.ConstructTable();
        Table table = director.GetTable();
    
        using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(fileName, true))
        {
    	var mainPart = wordDoc.MainDocumentPart;
    
    	var body = wordDoc.MainDocumentPart.Document.Body;
    
    	body.AppendChild<Table>(table);
        }
    }
    

    Any suggestions on making this better is appreciated.

  • I believe you can make some improvements in this code, but it may not make much difference in performance on small documents. However, it is always nice to have shorter code. Here is my code snippet, followed by an explanation:

     

    foreach (SdtBlock item in wordDoc.MainDocumentPart.Document.Body.Descendants<SdtBlock>()
        .Where(e => e.Descendants<SdtAlias>().FirstOrDefault().Val == controlName))
    {
        item.InsertAfterSelf(CreateTableWithBuilder(
            item.Descendants<Run>().Aggregate(new StringBuilder(), (s, i) => 
    s.Append(i.InnerText)).ToString())); }

     

    The idea here is to insert the newly created table immediately after the content control. The Where expression allows evaluation on the contents of the SdtBlock, but still returns the enumerator on the SdtBlock, not its descendants.

    For the CreateTableWithBuilder method, I am assuming that the text comes from the content control itself. Since there can be multiple runs, I am aggregating multiple runs into a single string that is passed to that method. Note that I don't need to step through every level of the hierarchy of elements.

  • bobm, this is awesome! This is just what I needed.  Thanks.

  • Is it possible to insert this inside a contenc control. Since I am generating a table. And i want to append that table inside the content control... what and all needs to be done?

  • I don't think you can put the table "inside" the content control. As I show in the example above, it can be inserted immediately after the content control.

  • Yes we can insert, Was able to do it now. By using adding to decedents.

  • Why don't you create tables in templates and use content controls to mark repeating rows in tables and placeholders this way you can create a more generic data driven document generation solution. You can check this toolkit to get the idea.

    And yes, you can nest tables inside content controls.

Page 1 of 1 (7 items)