Variables in text boxes do not get replaced
See original GitHub issueHow To Reproduce:
- Create a new blank document.
- Create a text box.
- Add a variable in the text box.
Outcome after processing: the variable (which exists in the context object) does not get replaced.
The reason:
Docxstamper only processes paragraphs and tables at the root level of the document. Text boxes are within AlternateContent tags and these elements contain paragraphs, but the paragraphs are never processed because AlternateContent is ignored.
The fix:
The main class for this is ‘CoordinatesWalker’. Docxstamper only supports paragraphs at the root nodes of the document. But it also gets any tables at the root nodes and iterates through the rows and cells to see if there are any paragraphs, which it then processes (using a ‘walkParagraph’ method). This essentially means that it will miss any paragraphs that aren’t in the root node and aren’t in tables. A text box is an example of a an element that will be skipped. So I think that the current approach in ‘CoordinatesWalker’ is probably unnecessary. All we really need to do is iterate through the whole document, grab all the paragraphs elements, stick them in a list and then process them using the ‘walkParagraph’ method.
Luckily, docx4j already provides a method to get all paragraphs (or any other element for that matter):
public static List<P> getAllParagraphsFromObject(Object obj) {
ClassFinder finder = new ClassFinder(P.class); // docx4j class
new TraversalUtil(obj,finder); // docx4j class
return getParagraphListFromObjectList(finder.results);
}
private static List<P> getParagraphListFromObjectList(List<Object> objectList) {
List<P> paragraphList = new ArrayList<>();
for (Object object: objectList) {
if (object instanceof P) {
paragraphList.add((P)object);
}
}
return paragraphList;
}
So all we do is get all the paragraphs and run them through the ‘walkParagraph’ method":
List<P> paragraphs = DocumentWrapper.getParagraphs(document);
for (P paragraph: paragraphs) {
// TODO remove the index, as it's not needed
ParagraphCoordinates coordinates = new ParagraphCoordinates(paragraph, 0);
walkParagraph(coordinates);
}
This works perfectly. You might notice that the index is always passed in as zero as the paragraph. coordinates. I haven’t had time to refactor this just yet, but in fact, coordinates aren’t actually needed at all. I think the original idea behind them was so that you might need them in order to delete elements, but you can delete elements using only the element itself because every element contains a reference to its parent. It’s basically this:
((ContentAccessor)paragraphCoordinates.getParagraph().getParent()).getContent().remove(
paragraphCoordinates.getParagraph());
Anyway, I hope the above helps someone who encounters the same issue. I am working on a project where I don’t have to much control over the input templates, so I don’t really have the luxury of telling the user “just don’t use text boxes”, and besides, there’s no good reason why we shouldn’t support them.
Issue Analytics
- State:
- Created 2 years ago
- Comments:8
You could be absolutely right. I will complete my testing and report back. Thx
see https://github.com/verronpro/docx-stamper/pull/36