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
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+");
}