Firstly I had to change the sdt Tag as it was hardcoded (an easy fix), but more importantly, when calling it using the following code, it writes to 2 content controls below 2 different bookmarks, not just the one specified:
Document doc = new Document(filenameAndPath);
FindReplaceOptions options = new FindReplaceOptions();
FindAndReplace findAndReplace = new FindAndReplace
{
BookmarkName = bookmarkName,
InsertionText = insertionText,
ContentControlTag = contentControlTag
};
options.ReplacingCallback = findAndReplace;
doc.Range.Replace(new Regex(searchText), searchText, options);
doc.Save(filenameAndPath);
}
private class FindAndReplace : IReplacingCallback
{
public object BookmarkName { get; internal set; }
public string InsertionText { get; internal set; }
public string ContentControlTag { get; internal set; }
ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
{
// This is a Run node that contains either the beginning or the complete match.
Node currentNode = e.MatchNode;
// The first (and may be the only) run can contain text before the match,
// in this case it is necessary to split the run.
if (e.MatchOffset > 0)
currentNode = SplitRun((Run)currentNode, e.MatchOffset);
// This array is used to store all nodes of the match for further removing.
ArrayList runs = new ArrayList();
// Find all runs that contain parts of the match string.
int remainingLength = e.Match.Value.Length;
while ((remainingLength > 0) &&
(currentNode != null) &&
(currentNode.GetText().Length <= remainingLength))
{
runs.Add(currentNode);
remainingLength = remainingLength - currentNode.GetText().Length;
// Select the next Run node.
// Have to loop because there could be other nodes such as BookmarkStart etc.
do
{
currentNode = currentNode.NextSibling;
}
while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
}
// Split the last run that contains the match if there is any text left.
if ((currentNode != null) && (remainingLength > 0))
{
SplitRun((Run)currentNode, remainingLength);
runs.Add(currentNode);
}
// To do
Document doc = ((Document)e.MatchNode.Document);
Bookmark bm = doc.Range.Bookmarks[BookmarkName.ToString()];
Paragraph bmPara = (Paragraph)bm.BookmarkStart.GetAncestor(NodeType.Paragraph);
if (bmPara != null)
{
int bmParaIndex = doc.GetChildNodes(NodeType.Paragraph, true).IndexOf(bmPara);
Paragraph start = ((Run)runs[0]).ParentParagraph;
int searchTextParaIndex = doc.GetChildNodes(NodeType.Paragraph, true).IndexOf(start);
if (searchTextParaIndex > bmParaIndex)
{
StructuredDocumentTag targetSdt = null;
Paragraph para = start;
bool flag = true;
while (para != null && flag)
{
foreach (StructuredDocumentTag sdt in para.GetChildNodes(NodeType.StructuredDocumentTag, true))
{
if (sdt.Tag.Equals(ContentControlTag))
{
targetSdt = sdt;
flag = false;
break;
}
}
para = (Paragraph)para.NextSibling;
}
if (targetSdt != null)
{
targetSdt.IsShowingPlaceholderText = false;
Run newTextRun = new Run(start.Document, InsertionText);
newTextRun.Font.Name = "Arial";
newTextRun.Font.Size = 10;
targetSdt.RemoveAllChildren();
if (targetSdt.Level == MarkupLevel.Inline)
{
targetSdt.AppendChild(newTextRun);
}
if (targetSdt.Level == MarkupLevel.Block)
{
para.ParagraphFormat.Alignment = ParagraphAlignment.Left;
para.AppendChild(newTextRun);
targetSdt.AppendChild(para);
}
}
}
}
return ReplaceAction.Skip;
}
private static Run SplitRun(Run run, int position)
{
Run afterRun = (Run)run.Clone(true);
afterRun.Text = run.Text.Substring(position);
run.Text = run.Text.Substring((0), (0) + (position));
run.ParentNode.InsertAfter(afterRun, run);
return afterRun;
}
}
private static void WriteFieldAfter(string filenameAndPath, string outputfilenameAndPath, string bookmarkName, string searchText, string contentControlTag, string insertionText)
{
Document doc = new Document(filenameAndPath);
FindReplaceOptions options = new FindReplaceOptions();
FindAndReplace findAndReplace = new FindAndReplace
{
BookmarkName = bookmarkName,
InsertionText = insertionText,
ContentControlTag = contentControlTag
};
options.ReplacingCallback = findAndReplace;
doc.Range.Replace(new Regex(searchText), searchText, options);
doc.Save(outputfilenameAndPath);
}
private class FindAndReplace : IReplacingCallback
{
public object BookmarkName { get; internal set; }
public string InsertionText { get; internal set; }
public string ContentControlTag { get; internal set; }
ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
{
// This is a Run node that contains either the beginning or the complete match.
Node currentNode = e.MatchNode;
// The first (and may be the only) run can contain text before the match,
// in this case it is necessary to split the run.
if (e.MatchOffset > 0)
currentNode = SplitRun((Run)currentNode, e.MatchOffset);
// This array is used to store all nodes of the match for further removing.
ArrayList runs = new ArrayList();
// Find all runs that contain parts of the match string.
int remainingLength = e.Match.Value.Length;
while ((remainingLength > 0) &&
(currentNode != null) &&
(currentNode.GetText().Length <= remainingLength))
{
runs.Add(currentNode);
remainingLength = remainingLength - currentNode.GetText().Length;
// Select the next Run node.
// Have to loop because there could be other nodes such as BookmarkStart etc.
do
{
currentNode = currentNode.NextSibling;
}
while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
}
// Split the last run that contains the match if there is any text left.
if ((currentNode != null) && (remainingLength > 0))
{
SplitRun((Run)currentNode, remainingLength);
runs.Add(currentNode);
}
// To do
Document doc = ((Document)e.MatchNode.Document);
Bookmark bm = doc.Range.Bookmarks[BookmarkName.ToString()];
Paragraph bmPara = (Paragraph)bm.BookmarkStart.GetAncestor(NodeType.Paragraph);
if (bmPara != null)
{
int bmParaIndex = doc.GetChildNodes(NodeType.Paragraph, true).IndexOf(bmPara);
Paragraph start = ((Run)runs[0]).ParentParagraph;
int searchTextParaIndex = doc.GetChildNodes(NodeType.Paragraph, true).IndexOf(start);
if (searchTextParaIndex > bmParaIndex)
{
StructuredDocumentTag targetSdt = null;
Paragraph para = start;
bool flag = true;
while (para != null && flag)
{
foreach (StructuredDocumentTag sdt in para.GetChildNodes(NodeType.StructuredDocumentTag, true))
{
if (sdt.Tag.Equals(ContentControlTag))
{
targetSdt = sdt;
flag = false;
break;
}
}
para = (Paragraph)para.NextSibling;
}
if (targetSdt != null)
{
targetSdt.IsShowingPlaceholderText = false;
Run newTextRun = new Run(start.Document, InsertionText);
newTextRun.Font.Name = "Arial";
newTextRun.Font.Size = 10;
targetSdt.RemoveAllChildren();
if (targetSdt.Level == MarkupLevel.Inline)
{
targetSdt.AppendChild(newTextRun);
}
if (targetSdt.Level == MarkupLevel.Block)
{
para.ParagraphFormat.Alignment = ParagraphAlignment.Left;
para.AppendChild(newTextRun);
targetSdt.AppendChild(para);
}
return ReplaceAction.Stop;
}
}
}
return ReplaceAction.Skip;
}
private static Run SplitRun(Run run, int position)
{
Run afterRun = (Run)run.Clone(true);
afterRun.Text = run.Text.Substring(position);
run.Text = run.Text.Substring((0), (0) + (position));
run.ParentNode.InsertAfter(afterRun, run);
return afterRun;
}
}
Sorry one more question (hopefully!), how would I do exactly the same thing but without having search text? In other words, I want to populate the first empty content control that comes after a specified bookmark but I won’t be using any search text this time so just the first empty content control with the specified tag that is found under the specified bookmark name.
I was hoping that I could simply set a bookmark and builder objects and move to the bookmark start and then loop round any child nodes of the bookmark and read their content control tags, but it seems that this is not possible.
Here is the sample document and expected output. Note that as before I want to have the bookmark name, filename, content control tag and insertion text to all be generic but this time I don’t want to include any search text. Many thanks…
Oops, spoke to soon. This generates the following error, presumably when encountering a table:
Unable to cast object of type ‘Aspose.Words.Tables.Table’ to type ‘Aspose.Words.Paragraph’.
I’m just trawling through the test data to see if I can spot what caused it as I was running multiple files when it crashed and I can’t step through as I’m running through 3rd party software. Will let you know if I spot the culprit.
private static void WriteSingleFieldValue_NoSearch(string filenameAndPath, string bookmarkName, string contentControlTag, string insertionText)
{
Document doc = new Document(filenameAndPath);
Bookmark bm = doc.Range.Bookmarks[bookmarkName];
Paragraph start = (Paragraph)bm.BookmarkStart.GetAncestor(NodeType.Paragraph);
StructuredDocumentTag targetSdt = null;
Paragraph para = (Paragraph)start;
bool flag = true;
while (para != null && flag)
{
foreach (StructuredDocumentTag sdt in para.GetChildNodes(NodeType.StructuredDocumentTag, true))
{
if ((sdt.Tag.Equals(contentControlTag))
&& ((sdt.ToString(SaveFormat.Text).Trim().Equals("Click or tap here to enter text."))
|| (sdt.ToString(SaveFormat.Text).Trim().Equals(""))
|| (sdt.ToString(SaveFormat.Text).Trim().Equals(contentControlTag))
|| sdt.ToString(SaveFormat.Text).Trim().Equals(contentControlTag + "_" + contentControlTag)))
{
targetSdt = sdt;
flag = false;
break;
}
}
para = (Paragraph)para.NextSibling;
}
if (targetSdt != null)
{
targetSdt.IsShowingPlaceholderText = false;
Run newTextRun = new Run(start.Document, insertionText);
newTextRun.Font.Name = "Arial";
newTextRun.Font.Size = 10;
targetSdt.RemoveAllChildren();
targetSdt.AppendChild(newTextRun);
}
doc.Save(filenameAndPath);
}
I am afraid, we do not see any Bookmarks in your newly shared ‘Sample With Table.docx’ document. Can you please also share your expected document showing the desired output? Also, how are you calling the ‘WriteSingleFieldValue_NoSearch’ method i.e. what are the parameter values you are supplying to this method?
WriteSingleFieldValue_NoSearch(@“c:\temp\Sample With Table.docx”,@“c:\temp\Sample With Table Output.docx”, “LimitOfLiability”, “contract_fields_claimsprep_value”, “99999”);
private static void WriteSingleFieldValue_NoSearch(string filenameAndPath, string outputFilenameAndPath, string bookmarkName, string contentControlTag, string insertionText)
{
Document doc = new Document(filenameAndPath);
Bookmark bm = doc.Range.Bookmarks[bookmarkName];
Paragraph start = (Paragraph)bm.BookmarkStart.GetAncestor(NodeType.Paragraph);
StructuredDocumentTag targetSdt = null;
Paragraph para = (Paragraph)start;
bool flag = true;
while (para != null && flag)
{
foreach (StructuredDocumentTag sdt in para.GetChildNodes(NodeType.StructuredDocumentTag, true))
{
if ((sdt.Tag.Equals(contentControlTag))
&& ((sdt.ToString(SaveFormat.Text).Trim().Equals("Click or tap here to enter text."))
|| (sdt.ToString(SaveFormat.Text).Trim().Equals(""))
|| (sdt.ToString(SaveFormat.Text).Trim().Equals(contentControlTag))
|| sdt.ToString(SaveFormat.Text).Trim().Equals(contentControlTag + "_" + contentControlTag)))
{
targetSdt = sdt;
flag = false;
break;
}
}
para = (Paragraph)para.NextSibling;
}
if (targetSdt != null)
{
targetSdt.IsShowingPlaceholderText = false;
Run newTextRun = new Run(start.Document, insertionText);
newTextRun.Font.Name = "Arial";
newTextRun.Font.Size = 10;
targetSdt.RemoveAllChildren();
targetSdt.AppendChild(newTextRun);
}
doc.Save(outputFilenameAndPath);
}