Aspose.Words

How-to: Rename Merge Fields

An example that shows how to create your own MergeField class, that represents a single merge field in a Microsoft Word document and allows you to get or set its name.

Example RenameMergeFields

Shows how to rename merge fields in a Word document.

[Java]

 

package Examples;

 

import org.testng.annotations.Test;

import com.aspose.words.Document;

import com.aspose.words.NodeCollection;

import com.aspose.words.NodeType;

import com.aspose.words.FieldStart;

import com.aspose.words.FieldType;

import com.aspose.words.Run;

import com.aspose.words.Node;

 

import java.util.regex.Matcher;

import java.util.regex.Pattern;

 

 

/**

* Shows how to rename merge fields in a Word document.

*/

public class ExRenameMergeFields extends ExBase

{

    /**

     * Finds all merge fields in a Word document and changes their names.

     */

    public void renameMergeFields() throws Exception

    {

        // Specify your document name here.

        Document doc = new Document(getMyDir() + "RenameMergeFields.doc");

 

        // Select all field start nodes so we can find the merge fields.

        NodeCollection fieldStarts = doc.getChildNodes(NodeType.FIELD_START, true);

        for (FieldStart fieldStart : (Iterable<FieldStart>) fieldStarts)

        {

            if (fieldStart.getFieldType() == FieldType.FIELD_MERGE_FIELD)

            {

                MergeField mergeField = new MergeField(fieldStart);

                mergeField.setName(mergeField.getName() + "_Renamed");

            }

        }

 

        doc.save(getMyDir() + "RenameMergeFields Out.doc");

    }

}

 

/**

* Represents a facade object for a merge field in a Microsoft Word document.

*/

class MergeField

{

    MergeField(FieldStart fieldStart) throws Exception

    {

        if (fieldStart.equals(null))

            throw new IllegalArgumentException("fieldStart");

        if (fieldStart.getFieldType() != FieldType.FIELD_MERGE_FIELD)

            throw new IllegalArgumentException("Field start type must be FieldMergeField.");

 

        mFieldStart = fieldStart;

 

        // Find the field separator node.

        mFieldSeparator = findNextSibling(mFieldStart, NodeType.FIELD_SEPARATOR);

        if (mFieldSeparator == null)

            throw new IllegalStateException("Cannot find field separator.");

 

        // Find the field end node. Normally field end will always be found, but in the example document

        // there happens to be a paragraph break included in the hyperlink and this puts the field end

        // in the next paragraph. It will be much more complicated to handle fields which span several

        // paragraphs correctly, but in this case allowing field end to be null is enough for our purposes.

        mFieldEnd = findNextSibling(mFieldSeparator, NodeType.FIELD_END);

    }

 

    /**

     * Gets or sets the name of the merge field.

     */

    String getName() throws Exception

    {

        String fieldResult = getTextSameParent(mFieldSeparator.getNextSibling(), mFieldEnd);

        int startPos = fieldResult.indexOf("«");

        startPos = (startPos >= 0) ? startPos + 1 : 0;

 

        int endPos = fieldResult.indexOf("»");

        endPos = (endPos >= 0) ? endPos : fieldResult.length();

 

        return fieldResult.substring(startPos, endPos);

    }

    void setName(String value) throws Exception

    {

        // Merge field name is stored in the field result which is a Run

        // node between field separator and field end.

        Run fieldResult = (Run)mFieldSeparator.getNextSibling();

        fieldResult.setText(java.text.MessageFormat.format("«{0}»", value));

 

        // But sometimes the field result can consist of more than one run, delete these runs.

        removeSameParent(fieldResult.getNextSibling(), mFieldEnd);

 

        updateFieldCode(value);

    }

 

    private void updateFieldCode(String fieldName) throws Exception

    {

        // Field code is stored in a Run node between field start and field separator.

        Run fieldCode = (Run)mFieldStart.getNextSibling();

        Matcher matcher = G_REGEX.matcher(fieldCode.getText());

 

        matcher.find();

 

        String newFieldCode = java.text.MessageFormat.format(" {0}{1} ", matcher.group(1).toString(), fieldName);

        fieldCode.setText(newFieldCode);

 

        // But sometimes the field code can consist of more than one run, delete these runs.

        removeSameParent(fieldCode.getNextSibling(), mFieldSeparator);

    }

 

    /**

     * Goes through siblings starting from the start node until it finds a node of the specified type or null.

     */

    private static Node findNextSibling(Node startNode, int nodeType) throws Exception

    {

        for (Node node = startNode; node != null; node = node.getNextSibling())

        {

            if (node.getNodeType() == nodeType)

                return node;

        }

        return null;

    }

 

    /**

     * Retrieves text from start up to but not including the end node.

     */

    private static String getTextSameParent(Node startNode, Node endNode) throws Exception

    {

        if ((endNode != null) && (startNode.getParentNode() != endNode.getParentNode()))

            throw new IllegalArgumentException("Start and end nodes are expected to have the same parent.");

 

        StringBuilder builder = new StringBuilder();

        for (Node child = startNode; !child.equals(endNode); child = child.getNextSibling())

            builder.append(child.getText());

 

        return builder.toString();

    }

 

    /**

     * Removes nodes from start up to but not including the end node.

     * Start and end are assumed to have the same parent.

     */

    private static void removeSameParent(Node startNode, Node endNode) throws Exception

    {

        if ((endNode != null) && (startNode.getParentNode() != endNode.getParentNode()))

            throw new IllegalArgumentException("Start and end nodes are expected to have the same parent.");

 

        Node curChild = startNode;

        while ((curChild != null) && (curChild != endNode))

        {

            Node nextChild = curChild.getNextSibling();

            curChild.remove();

            curChild = nextChild;

        }

    }

 

    private final Node mFieldStart;

    private final Node mFieldSeparator;

    private final Node mFieldEnd;

 

    private static final Pattern G_REGEX = Pattern.compile("\\s*(MERGEFIELD\\s|)(\\s|)(\\S+)\\s+");

}