Aspose word field


#1

Hi,
How can I replace some String to Field in a word?
Thanks.


#2

@liuyahui,

Attachment: template.zip (10.0 KB)

For example, you can replace plain text in Word document with real merge fields by using following code of Aspose.Words for .NET.

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

FindReplaceOptions opts = new FindReplaceOptions();
opts.ReplacingCallback = new ReplaceWithMergefield();
opts.Direction = FindReplaceDirection.Backward;
doc.Range.Replace(new Regex(@"\{(.*?)\}"), "", opts);

doc.Save("E:\\temp\\19.10.docx");

private class ReplaceWithMergefield : IReplacingCallback
{
    public ReplaceAction 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);
        }

        DocumentBuilder builder = new DocumentBuilder((Document)e.MatchNode.Document);
        builder.MoveTo((Run)runs[runs.Count - 1]);

        builder.InsertField("MERGEFIELD \"" + e.Match.Groups[1].Value.Trim() + "\"", null);

        //Now remove all runs in the sequence.
        foreach (Run run in runs)
            run.Remove();

        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, position);
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }
}

Hope, this helps in achieving what you are looking for.


#3

sorry, I forgot to mention it, I use java ,do you have any java code?
Thanks a lot


#4

@liuyahui,

Attachments: convert placeholders to real mergefields.zip (19.5 KB)

You can build logic on the following Aspose.Words for Java code to get the desired output:

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

Pattern pattern = Pattern.compile("\\{(.*?)\\}");

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

doc.getRange().replace(pattern, "", opts);

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

static class ReplaceWithMergefield 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 do
        DocumentBuilder builder = new DocumentBuilder((Document)e.getMatchNode().getDocument());
        builder.moveTo((Run)runs.get(runs.size()-1));
        builder.insertField("MERGEFIELD \""+e.getMatch().group(1) + "\"", null);

        System.out.println("MERGEFIELD \""+e.getMatch().group(1) + "\"");

        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;
    }
}

#5

ok, thanks a lot.