Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenXml Table error "<p> elements are required before every </tc>"

I have created a Word template that I am then processing via the OpenXML SDK to replace some of the content of the document with data from a database query.

The template consists of some basic text with Plain Text Content controls injected in the places that I want to replace the text. I am then using the text in these controls as a key to lookup the replacement values. In most cases, this is working fine (I simply update the Text property of the Text object).

In one case I am replacing the text with a table. In this case, I build up a table in code and then I replace the content of the SdtContentRun object (the parent of the Run object, which in turn is the parent of the Text object) with the new Table object...

var sdtContentRunElements =
  from sdtContentRun in this.Document.MainDocumentPart.RootElement.Descendants<SdtContentRun>()
  select sdtContentRun;

sdtContentRunElements.ForEach(sdtContentRunElement => {

  Run firstRunElement = sdtContentRunElement.Descendants<Run>().FirstOrDefault();
  if (firstRunElement != null) {

    Text firstTextElement = firstRunElement.Descendants<Text>().FirstOrDefault();
    if (firstTextElement != null) {

      switch (firstTextElement.Text) {

        case TableBookmark:

          Table advisoryTable = new Table(...); // See below
          OpenXmlElement parent = firstRunElement.Parent;
          parent.RemoveAllChildren();
          parent.Append(advisoryTable);
          break;

        case ContractorItemAdvisoriesLetter.ContractorCodeBookmark:

          firstTextElement.Text = @"New text";
          break;

      }
    }
  }
}

}

This results in the following XML (taken from the Open XML SDK 2.0 Productivity Tool for Microsoft Office)...

<w:sdtContent xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:tbl>
    <w:tr>
      <w:tc>
        <w:p>
          <w:r>
            <w:t>Lorem ipsum dolor sit amet</w:t>
          </w:r>
        </w:p>
      </w:tc>
    </w:tr>
  </w:tbl>
</w:sdtContent>

(Some of the content of the table has been removed as I felt it would simply cloud the issue)

When I then try to open the document in Word, I get an error. The error being reported is...

Ambuguous cell mapping encountered. Possible missing paragraph element. <p> elements are required before every </tc>

It is probably worth mentioning that when I view the document explorer in Open XML SDK 2.0 Productivity Tool for Microsoft Office, the w:tbl element (and all elements contained within) are being recognised as OpenXmlUnknownElement rather than being recognised as Table objects. I do not know if this is relevant or whether it is a quirk of the SDK tool.

Clearly I am missing something. As far as I can tell from the Table class definition, it is perfectly legal to place a w:tbl inside a w:sdtContent (unless I am reading this incorrectly) so I am now at a loss as to what the problem may be. There are also very few results if you google "Table" and "OpenXmlUnknownElement" with none of the results appearing to be related to my problem.

Any suggestions?

EDIT: Further investigation seems to indicate that the problem actually lies in the embedding of another table within one of the cells of the table being added above. The new Table object is being added directly to a TableCell object which again, according to the documentation for Table referenced above, should be acceptable...

Table advisoryTable = new Table();

advisories.ForEach(advisory => {

    advisoryTable.Append(new TableRow(new TableCell(new Paragraph(new Run(new Text(advisory.NoteText))))));

    advisory.ItemAdvisories.ForEach(itemAdvisory => {

        Item item = itemAdvisory.Item;

        Table itemTable = new Table();
        itemTable.Append(new TableRow[] {

            new TableRow(new TableCell[] {
                new TableCell(new Paragraph(new Run(new Text(string.Format(@"Item {0}", item.Sequence)))))
            })

        });

        advisoryTable.Append(new TableRow(new TableCell(itemTable)));

    });

});

Resulting in...

<w:tbl xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:tr>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>Lorem ipsum dolor sit amet</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:tbl>
        <w:tr>
          <w:tc>
            <w:p>
              <w:r>
                <w:t>Item 1</w:t>
              </w:r>
            </w:p>
          </w:tc>
        </w:tr>
      </w:tbl>
    </w:tc>
  </w:tr>
</w:tbl>

I have tried adding a Paragraph between the TableCell and the embedded Table, but this simply results in a new error, this time "unspecified error".

like image 471
Martin Robins Avatar asked Nov 28 '11 16:11

Martin Robins


1 Answers

Sorted. The original error message could not really have been any clearer!

The last child of a table cell must be a paragraph. Simply adding an empty paragraph after the embedded table resolved the problem...

advisoryTable.Append(new TableRow(new TableCell(itemTable, new Paragraph())));

I eventually discovered this by creating a document in Word-2010 that consisted of a table within a table and then looking at the resulting XML in the same Open XML SDK 2.0 Productivity Tool for Microsoft Office tool used above.

like image 51
Martin Robins Avatar answered Oct 27 '22 20:10

Martin Robins