Generic/empty fields


#1

Sometime back I asked about Merging an image into a Generic Fields (believe you guys called them empty fields). And leaving this field in place so the image could be removed (Un-merge). I thought you said there was a way to do this, but I can’t find those emails or any postings in the forums about it.

Basically I need to insert a image at/in the field in the attached document. And Possibly then find the field again and remove the image. In both cases modifing the text contained in the field.

Is this possible?


#2

{ IF 0 = 0 “{ProvidersSignature}” “” * MERGEFORMAT }

In your document you create a “generic field” using an approach that looks like a workaround. Basically you request MS Word to evaluate the “0 = 0” expression which evaluates always to true and insert text “{ProvidersSignature}” into the document.

The point to keep in mind with fields in MS Word is that you cannot do things with them they were not supposed to. For example, for most of the fields, it is pointless to modify text or result of the field because when MS Word recalculates the fields it will replace the result with a calculated value discarding your content.

What I’m saying is that if you insert something into the result of this field and the fields are later recalculated, your insertion will be discarded.

I somewhat recall our earlier conversation, but I think I ended up exactly on the same note. Aspose.Word does not support this approach and does not leave any filled merge fields in the document because of the issue I just mentioned.


#3

If you want to play or experiment yourself, please use Aspose.Word 3.0. It might be possible to do what you want (but keep in mind that MS Word will recalc your fields).

In the document tree your field will be represented like this:

[FieldStart]
[one or more Run with " IF 0 = 0 "{ProvidersSignature}" "" \* MERGEFORMAT "]
[FieldSeparator]
[one or more Run with "{ProvidersSignature}"]
[FieldEnd]

The FieldType property of the FieldStart node will be equal to FieldType.FieldIf.

If you want to insert something into this field, you need to do this:
1. Find a FieldStart node with the proper FieldType.
2. Parse Runs between FieldStart and FieldSeparator to find the field name "ProvidersSignature".
3. Remove all nodes between FieldSeparator and FieldEnd.
4. Insert your text (one or more Run) or an image between FieldSeparator and FieldEnd. The best way to insert text or image in this case will be to create a DocumentBuilder and call DocumentBuilder.MoveTo(FieldEnd) and then DocumentBuilder.InsertImage.


#4

Thanks Roman. I will look at what I can do there. We are about to redo this interface to use true merge fields. Can you provide a solution to this problem using true merge fields. Could DocumentBuilder be used to find and merge the image, and then insert a new field right before or after? Could you then find the new field and get to the image right before or after and remove it?


#5

If you want to insert and then remove and then insert data again at some location, the best approach is to use bookmarks as they are invisible and stay after the data is inserted. Normal mail merge fields suffer the same issue as any other fields - MS Word will recalculate their result and default result of a merge field is <>.

With Aspose.Word 3.0 it is possible to do all of what you mentioned above. You can find any field and move to it, find previous, next, parent etc nodes, insert nodes, remove them. Just let me know if you have specific questions and we will try to provide code examples where we can. We are working to create more code examples right now.


#6

Thanks Roman. I will download version 3.0 and play with it.


#7

OK, I think I’m close Roman. I have placed a bookmark in a document, I also have a InLineShape right after the bookmark. I’m able to find and update the text of the bookmark. I’ve even managed to find the InLineShape.

However I have to issues remaining.

1. How can I determine I have the correct InLineShape? I.e. How do I know the InLineShape is right after the bookmark?

2. I’ve tried using the Document.RemoveChild to remove the InlineShape (node). but it tells me it is not the parent of OldChild. How can I remove the InLineShape?

Code Sample:


doc = New Aspose.Word.Document(saveFileName)

bk = doc.Range.Bookmarks(“StartProviderSignature”)

'bk.Text = “Typed but not signed.”

bk.Text = “”

nd = doc.GetChild(Aspose.Word.NodeType.InlineShape, 0, True)

doc.RemoveChild(nd)



#8

doc.GetChild(Aspose.Word.NodeType.InlineShape, 0, True)

The above code will find a first InlineShape node in the document, not after the bookmark.

With the bookmarks you need to be aware that it consists of two nodes: BookmarkStart and BookmarkEnd that mark start and end of the bookmark in the document.

The Bookmark class is a “facade” that allows to work with both nodes as with a single bookmark object, therefore:

//This finds the “facade” (say user friendly) object that wrapsthe complete bookmark and text inside it.
Bookmark bk = doc.Range.Bookmarks(“StartProviderSignature”);

//This is the actual node in the document that is the start of the bookmark.
BookmarkStart bkStart = bk.BookmarkStart;

//This is the actual node in the document that is the end of the bookmark.
BookmarkEnd bkEnd = bk.BookmarkEnd;

//There are nodes between bkStart and bkEnd and of course nodes before and after them, you are inside a tree basically.

//If you want to access a node that is right after the bookmark end:
Node myNode = bkEnd.NextSibling;

//If you happen to want to remove that node, ask the parent of that node:
myNode.ParentNode.RemoveChild(myNode);

//If you want to loop through the nodes after the bookmark end, but at the same level, in the paragraph (say if the bookmark inside a paragraph), then do something like this:

for (Node node = bkEnd.NextSibling; node != null; node = node.NextSibling)
{
if (node.NodeType == NodeType.InlineShape)
{
//Found an inline shape after the bookmark end, do something, for example remove it.
node.ParentNode.Remove(node);
break;
}
}


//Maybe the node you are looking for is not after the end of the bookmark, but inside the bookmark? In this case go through all nodes from bookmark start to bookmark end.

//Just a sanity check that bookmarks have the same parent, otherwise iteration will not finish.
Debug.Assert(bkStart.ParentNode == bkEnd.ParentNode);
for (Node node = bkStart.NextSibling; node != bkEnd; node = node.NextSibling)
{
//Do something
}


--------------

Now you can see that dealing with nodes is pretty low level work, that’s why the Bookmark class exists, to make working with a bookmark easier.

For example, if you want to delete everything that is inside the bookmark and then insert, one of the possible ways will be:

Bookmark bk = doc.Range.Bookmarks(“StartProviderSignature”);

//This removes all nodes from the bookmark. Easy?
bk.Text = “”;

//You can use document builder to avoid dealing with nodes like this:
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveToBookmark(“StartProviderSignature”);
builder.InsertImage(myImage);

//Or you can use nodes directly if you want.
//Get the parent of the bookmark start node, it should be Paragraph.
Paragraph para = (Paragraph)bk.BookmarkStart.ParentNode;

//Insert a new piece of text after the bookmark start node.
para.InsertAfter(new Run(“New bookmark text”), bk.BookmarkStart);


#9

Thanks Roman, that information helped alot. I now have a working and workable solution.