Updating DocumentTagField sometimes throws exception 'Cannot add a node before/after itself'

I am updating document control tags and in some scenarios we are getting ‘Cannot add a node before/after itself’ but it works fine if we add a space before the tag.
I am curious to know why would it throw an error and why would it fix if we add a space.
I have attached the sample word document
failing-reviewmemo-prod.docx (39.2 KB)

using aspose-words-21.6.0.jdk17.jar

@mp2 Could you please provide code that will allow us to reproduce the problem? I trued with this code and SDT is updated correctly:

Document doc = new Document("C:\\Temp\\in.docx");
Iterable<StructuredDocumentTag> sdts = doc.getChildNodes(NodeType.STRUCTURED_DOCUMENT_TAG, true);
for (StructuredDocumentTag sdt : sdts)
{
    if (sdt.getSdtType() == SdtType.RICH_TEXT)
    {
        sdt.removeAllChildren();
        if (sdt.getLevel() == MarkupLevel.BLOCK)
        {
            Paragraph para = new Paragraph(doc);
            para.appendChild(new Run(doc, "This is updated text"));
            sdt.appendChild(para);
        }
        else if (sdt.getLevel() == MarkupLevel.INLINE)
        {
            sdt.appendChild(new Run(doc, "This is updated text"));
        }
    }
}
doc.save("C:\\Temp\\out.docx");

Here you go:

    public static void updateDocumentTagFields(Document doc, Map<String, String> props) throws Exception {
		String sdtTitle = "";
		// update the form fields
		NodeCollection<StructuredDocumentTag> contentControlCollection = doc
				.getChildNodes(NodeType.STRUCTURED_DOCUMENT_TAG, true);

		for (StructuredDocumentTag sdt : contentControlCollection) {
			sdtTitle = sdt.getTitle();
			HeaderFooter headerFooter = (HeaderFooter) sdt.getAncestor(NodeType.HEADER_FOOTER);
			if (props.containsKey(sdtTitle) && props.get(sdtTitle) != null) {
				try {
					switch (sdt.getSdtType()) {
					case SdtType.PLAIN_TEXT:
						updateRichText(doc, sdt, props.get(sdtTitle), (headerFooter == null) ? false : true);
						break;
					case SdtType.RICH_TEXT:
						updateRichText(doc, sdt, props.get(sdtTitle), (headerFooter == null) ? false : true);
						break;

					case SdtType.CHECKBOX:
						updateCheckBox(doc, sdt, props.get(sdtTitle));
						break;
					}
				} catch (Exception e) {
					throw new Exception("Error occured while updating DocumentTagField( " + sdtTitle + " = "
							+ props.get(sdtTitle) + " ) " + e.getMessage());
				}
			}
		}
	}

	public static void updateCheckBox(Document doc, StructuredDocumentTag sdt, String txtVal) throws Exception {
		if (txtVal.equalsIgnoreCase("true"))
			sdt.setChecked(true);
		else
			sdt.setChecked(false);
	}

	public static void updateTextNode(Document doc, StructuredDocumentTag sdt, String txtVal) throws Exception {
		sdt.removeAllChildren();
		Run run = new Run(doc, txtVal);
		sdt.appendChild(run);
	}

	public static void updateRichText(Document doc, StructuredDocumentTag sdt, String txtVal, boolean isHeaderPresent)
			throws Exception {

		if (isHeaderPresent) {
			// Get the first Run of text you want to keep formatting of
			Run firstRun = (Run) sdt.getChildNodes(NodeType.RUN, true).get(0);

			// Remove all other nodes
			if (firstRun != null)
				for (Node node : (Iterable<Node>) sdt.getChildNodes(NodeType.ANY, true))
					if (node != firstRun)
						node.remove();

			// Update the text of first Run
			firstRun.setText(txtVal);
		} else {
			Run run = new Run(doc);
			run.setText(txtVal);

			if (sdt.getLevel() == MarkupLevel.INLINE) {
				sdt.removeAllChildren();
				sdt.getChildNodes().add(run);
			} else if (sdt.getLevel() == MarkupLevel.BLOCK) {
				sdt.removeAllChildren();
				Paragraph para = (Paragraph) sdt.appendChild(new Paragraph(doc));
				para.getRuns().add(run);
				sdt.getChildNodes().add(para);
			} else if (sdt.getLevel() == MarkupLevel.CELL) {
				if (sdt.getFirstChild().getNodeType() == NodeType.CELL) {
					Cell cell = (Cell) sdt.getFirstChild();
					cell.removeAllChildren();
					cell.ensureMinimum();
					Paragraph para = ((Cell) sdt.getFirstChild()).getFirstParagraph();
					para.getRuns().add(run);
				}
			}
		}
	}

@maaaruf Thank you for additional information. There is a mistake in your code. See the following snippet:

} else if (sdt.getLevel() == MarkupLevel.BLOCK) {
	sdt.removeAllChildren();
	Paragraph para = (Paragraph) sdt.appendChild(new Paragraph(doc));
	para.getRuns().add(run);
	sdt.getChildNodes().add(para);

You add the paragraph to SDT here:

Paragraph para = (Paragraph) sdt.appendChild(new Paragraph(doc));

and again here:

sdt.getChildNodes().add(para);

You should modify this code like the following:

} else if (sdt.getLevel() == MarkupLevel.BLOCK) {
    sdt.removeAllChildren();
    Paragraph para = (Paragraph) sdt.appendChild(new Paragraph(doc));
    para.appendChild(run);

thank you very much Alexey…that worked…you guys are best!

1 Like