Bug 66363 - XWPFDocument.insertTable doesn't work at all
Summary: XWPFDocument.insertTable doesn't work at all
Status: NEW
Alias: None
Product: POI
Classification: Unclassified
Component: XWPF (show other bugs)
Version: 5.2.2-FINAL
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: POI Developers List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-11-24 13:47 UTC by Nigel Gay
Modified: 2022-11-28 12:18 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nigel Gay 2022-11-24 13:47:57 UTC
XWPFDocument.insertTable does not seem to work at all.  Created small example word doc that looks like:

0: Paragraph 1
1: Table 1
2: Paragraph 2
3: Paragraph 3
4: Table 2
5: Paragraph 4

The indexes are what's in the bodyElements array.  Verified its being read as expected. Then running this example on it:

try (XWPFDocument doc = new XWPFDocument (getClass ().getResourceAsStream ("/InsertTable.docx")))
{
	// This is just here to verify the indexes into the bodyElements list are as expected
	int index = 0;
	for (IBodyElement elem : doc.getBodyElements ())
	{
		System.out.println (index + ": " + elem);
		index++;
	}
			
	// Copy one of the existing tables and insert it at specific point
	XWPFTable src = (XWPFTable) doc.getBodyElements ().get (1);
	XWPFTable dest = new XWPFTable ((CTTbl) src.getCTTbl ().copy (), doc);
	doc.insertTable (3, dest);

	File outFile = File.createTempFile ("TestInsertTable", ".docx");
	outFile.delete ();
			
	try (FileOutputStream out = new FileOutputStream (outFile))
	{
		doc.write (out);
	}
}

The copied table doesn't come out in the word doc at all.  Moreover if you look at what insertTable is doing, it adds the new table into the bodyElements list, but that's just an ArrayList so doing so doesn't trigger any special processing or updates of the underlying XML.  So then it is searching for where the newly added table XML (CTTbl) was added into the document XML, and fails to find it because nothing added it.  So then it defaults to adding the table at the end of the list of tables, but again this is just an ArrayList so isn't triggering any special processing or updating of the underlying XML.

If I use createTable instead of copying an existing table, the table does get added, but at the end of the doc instead of at the desired index into the bodyElements list.  This is because createTable() has already called ctDocument.getBody().addNewTbl() and added at the end of the XML before we call insertTable to say where we actually want it.
Comment 1 Nigel Gay 2022-11-24 14:23:29 UTC
The only workaround I can find is to create an XmlCursor for the insertion point, then call XWPFDocument.insertNewTbl to create a throwaway table, then use XWPFDocument.setTable to replace the throwaway table with the real one.

public XmlCursor newCursorForBodyElement (IBodyElement elem)
{
	XmlCursor cursor;
	if (elem instanceof XWPFParagraph)
	{
		XWPFParagraph para = (XWPFParagraph) elem;
		cursor = para.getCTP ().newCursor ();
	}
	else if (elem instanceof XWPFTable)
	{
		XWPFTable table = (XWPFTable) elem;
		cursor = table.getCTTbl ().newCursor ();
	}
	else
		throw new RuntimeException ("Don't know how to create a cursor from body element of type " + elem.getClass ());
	
	return cursor;
}

.. and then can do ...

index = 3;
XWPFTable throwawayTable;
if (index < doc.getBodyElements ().size ())
{
	// Insert before numbered element
	XmlCursor insertionPoint = newCursorForBodyElement (doc.getBodyElements ().get (index));
	throwawayTable = doc.insertNewTbl (insertionPoint);
}
else
{
	// Insert at end
	throwawayTable = doc.createTable ();
}
			
doc.setTable (doc.getTables ().indexOf (throwawayTable), dest);
Comment 2 PJ Fanning 2022-11-24 21:08:40 UTC
There are some unreleased changes in XWPF code, eg https://bz.apache.org/bugzilla/show_bug.cgi?id=66312

Would you be able to try the latest code? You can build jars from latest source code or you could get jars from https://ci-builds.apache.org/job/POI/job/POI-DSL-1.8/
Comment 3 Nigel Gay 2022-11-28 12:18:40 UTC
Tried with latest JARs from Jenkins and find no difference.  I think its just not intended to be used the way I am expecting to be able to.