Replace variable (marker) in Word with Table

Hi guys,

My problem: How to replace a variable (ex. {{pricing.rent}}) by a simple table format with 2 columns and 2 rows.
With your examples, I easy to generate with format defined.

Is there any ideas?

Thanks,
Khoa

@khoapkl

Please try using the following code:

Document doc = new Document("E:\\temp\\in.docx");

FindReplaceOptions opts = new FindReplaceOptions();
opts.Direction = FindReplaceDirection.Backward;
opts.ReplacingCallback = new ReplaceEvaluator();

doc.Range.Replace("{{pricing.rent}}", "", opts);

doc.Save("E:\\Temp\\19.5.docx");

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 class ReplaceEvaluator : IReplacingCallback
{
    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 insert Table
        DocumentBuilder builder = new
        DocumentBuilder((Document)e.MatchNode.Document);

        builder.MoveTo((Run)runs[runs.Count - 1]);

        Table table = builder.StartTable();

        builder.InsertCell();
        builder.Write("This is row 1 cell 1");
        builder.InsertCell();
        builder.Write("This is row 1 cell 2");
        builder.EndRow();

        builder.InsertCell();
        builder.Writeln("This is row 2 cell 1");
        builder.InsertCell();
        builder.Writeln("This is row 2 cell 2");
        builder.EndRow();

        builder.EndTable();

        foreach (Run run in runs)
            run.Remove();

        return ReplaceAction.Skip;
    }
}

Hope, this helps.

Sorry, Awais! I’m working with Java language. Can you help me to change something?

My template includes 2 variables {{organization.name}} and {{pricing.rent}} in order position such as:

Organization name: {{organization.name}}

{{pricing.rent}}

@khoapkl,

Please try using the following Java code:

Document doc = new Document("E:\\Temp\\input.docx");

FindReplaceOptions opts = new FindReplaceOptions();
opts.setDirection(FindReplaceDirection.BACKWARD);
opts.setReplacingCallback(new ReplaceEvaluator());

doc.getRange().replace("{{pricing.rent}}", "", opts);

doc.save("E:\\Temp\\awjava-19.5.docx"); 

static class ReplaceEvaluator implements IReplacingCallback {
    public int replacing(ReplacingArgs e) throws Exception {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.getMatchNode();

        // 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.getMatchOffset() > 0)
            currentNode = splitRun((Run) currentNode, e.getMatchOffset());

        ArrayList runs = new ArrayList();

        // Find all runs that contain parts of the match string.
        int remainingLength = e.getMatch().group().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.getNextSibling();
            } while ((currentNode != null) && (currentNode.getNodeType() != 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 insert Table
        DocumentBuilder builder = new DocumentBuilder((Document)e.getMatchNode().getDocument());

        builder.moveTo((Run)runs.get(runs.size() - 1));

        Table table = builder.startTable();

        builder.insertCell();
        builder.write("This is row 1 cell 1");
        builder.insertCell();
        builder.write("This is row 1 cell 2");
        builder.endRow();

        builder.insertCell();
        builder.write("This is row 2 cell 1");
        builder.insertCell();
        builder.write("This is row 2 cell 2");
        builder.endRow();

        builder.endTable();

        for (Run run : (Iterable<Run>) runs)
            run.remove();

        // Signal to the replace engine to do nothing because we have already done all what we wanted.
        return ReplaceAction.SKIP;
    }

    /**
     * Splits text of the specified run into two runs. Inserts the new run just
     * after the specified run.
     */
    private Run splitRun(Run run, int position) throws Exception {
        Run afterRun = (Run) run.deepClone(true);
        afterRun.setText(run.getText().substring(position));
        run.setText(run.getText().substring((0), (0) + (position)));
        run.getParentNode().insertAfter(afterRun, run);
        return afterRun;
    }
}

Hope, this helps.

Thank so much!