Issue with nested If and autotext fileds

Hi,

We use aspose.net to merge lot of word docs and we use lots of autotext fields in addition to mergefields. Recently we have run into an issue whereby if we have nested if statements which use autotext fields in it, the merge and updatefield call to update the if conditions does not work properly.

I am attaching the example document StaticTable_Aspose.docx file which is my template and the merged document is out_merged.docx. As you can see if instead of using nested IFs, if we simpligy it using Compare syntax (My example document has two different IF condition in it, the first one does not work), it works OK but we have many cases where I can not simplify the multi layer nested Ifs into simple Ifs.

I am also pasting the code I am using in a standalone class for demonstration puprose, so that it is easy for you to reporduce the issue.

I am guessing, that my code to parse and replace the fieldcode and fieldvalue is not correct for nested If conditions, but I am not sure what changes will solve my problem.

I will appreciate if you can look and let me know what the issue is and how to solve it. Please let me now if I can help by providing any more info.

Thx

Thanmal.

The Code:

private static void Test5()
{
    Dictionary<string, string> dynamicFieldLabelValues = new Dictionary<string, string>();
    dynamicFieldLabelValues.Add("Buyer1Name", "ThanmalB1");
    dynamicFieldLabelValues.Add("Buyer1Type", "C");
    dynamicFieldLabelValues.Add("Buyer1Agent1NameTitle", "ThanmalB1Agent1");
    dynamicFieldLabelValues.Add("Buyer2Name", "ThanmalB2");
    dynamicFieldLabelValues.Add("Buyer2Type", "C");
    dynamicFieldLabelValues.Add("Buyer2Agent1NameTitle", "ThanmalB2Agent1");
    dynamicFieldLabelValues.Add("Buyer3Name", "ThanmalB3");
    dynamicFieldLabelValues.Add("Buyer4Name", "ThanmalB4");
    dynamicFieldLabelValues.Add("Seller1Name", "ThanmalSeller1");
    dynamicFieldLabelValues.Add("Seller1Type", "C");
    dynamicFieldLabelValues.Add("Seller1Agent1NameTitle", "ThanmalSeller1Agent1");
    dynamicFieldLabelValues.Add("Seller2Name", "ThanmalSeller2");
    dynamicFieldLabelValues.Add("Seller2Type", "C");
    dynamicFieldLabelValues.Add("Seller2Agent1NameTitle", "ThanmalSeller2Agent1");
    dynamicFieldLabelValues.Add("Seller3Name", "ThanmalSeller3");
    dynamicFieldLabelValues.Add("Seller4Name", "ThanmalSeller4");
    //dynamicFieldLabelValues.Add("Buyer2Type", "C");
    license = new License();
    license.SetLicense("Aspose.Words.lic");
    Document doc = new Document("C:\\StaticTable_Aspose.docx");
    //lets merge the autotext fields first
    //Create DocuentBuilder. It will help us to modify fields
    DocumentBuilder builder = new DocumentBuilder(doc);
    //Get collection of FieldStart nodes
    NodeCollection starts = doc.GetChildNodes(NodeType.FieldStart, true);
    //loop through all field starts and search for AutoText and Ask fields
    //as these are the only ones we use currently in our templates
    foreach (FieldStart start in starts)
    {
        if (start.FieldType == FieldType.FieldAutoText || start.FieldType == FieldType.FieldAsk || start.FieldType == FieldType.FieldFillIn)
        {
            Node fieldSeparator;
            Node fieldEnd;
            ////We should get field code and field value 
            string fieldCode = string.Empty;
            string fieldValue = string.Empty;
            string tempValue = string.Empty;
            string bookmark = string.Empty;
            Node currentNode = start.NextSibling;
            ////Get Field code
            while (currentNode.NodeType != NodeType.FieldSeparator)
            {
                if (currentNode.NodeType == NodeType.Run)
                    fieldCode += (currentNode as Run).Text;
                currentNode = currentNode.NextSibling;
                if (currentNode != null)
                    currentNode.PreviousSibling.Remove();
                if (currentNode == null)
                    break;
            }
            fieldSeparator = currentNode;
            currentNode = currentNode.NextSibling;
            string newValue = "";
            if (start.FieldType == FieldType.FieldAutoText)
            {
                //get the field value 
                tempValue = ParseAutoTextFields(fieldCode);
                Console.WriteLine(tempValue);
                //string newValue = "";
                if (dynamicFieldLabelValues.ContainsKey(tempValue))
                {
                    newValue = dynamicFieldLabelValues[tempValue].ToString();
                    Console.WriteLine(newValue);
                }
            }
            ////Get field value
            if (currentNode != null)
            {
                while (currentNode.NodeType != NodeType.FieldEnd)
                {
                    if (currentNode.NodeType == NodeType.Run)
                        fieldValue += (currentNode as Run).Text;
                    currentNode = currentNode.NextSibling;
                    if (currentNode != null && currentNode.PreviousSibling != null)
                        currentNode.PreviousSibling.Remove();
                    if (currentNode == null)
                        break;
                }
            }
            fieldEnd = currentNode;
            ////Insert new field code and field value
            builder.MoveTo(fieldSeparator);
            builder.Write(fieldCode);
            if (fieldEnd != null)
                builder.MoveTo(fieldEnd);
            builder.Write(newValue);
        }
    }
    //Call the method to update the if field values
    try
    {
        doc.UpdateFields();
    }
    catch (Exception ex)
    {
        //this might throw exception, log it and move on
        Console.WriteLine(ex.Message + ex.StackTrace);
    }
    doc.Save("c:/out_Merged.docx", Aspose.Words.SaveFormat.Docx);
    //Console.Read();
}

private static string ParseAutoTextFields(string fieldcode)
{
    string fieldcodeTemp = fieldcode.Trim().Substring(fieldcode.Trim().IndexOf("Autotext ", StringComparison.InvariantCultureIgnoreCase) + 9).Trim();
    return fieldcodeTemp.Replace("\\* Upper", "").Trim();
}

Hi,

Is anyone looking into this issue? This is happening with lots of our production templates and I will appreciate if someone can provide some insight. Please let me know if you need more info from me.

Thx

Thanmal.

Hi Thanmal,

Thanks for your inquiry and sorry for the delayed response. We’ve started working over your query and will get back to you soon.

Best Regards,

Hi Thanmal,

Thanks for your inquiry and sorry for the delayed response.

I further investigated the structure of your IF fields and found that this problem occurs because the expressions in your IF fields (e.g. { IF { autotext Buyer2Name }=“” “”) are not well formed. Please try supplying a valid expression e.g. { IF { autotext Buyer2Name } = “” “” (note the additional space around = sign) by editing those fields. I have made corrections to your StaticTable_Aspose.docx and attached a valid document here for your reference. Please let us know how it goes on your side.

Also, I would suggest you please use the latest version of Aspose.Words i.e 11.2.0. You can download it from the following link:

https://downloads.aspose.com/words/net

I hope, this will help.

Best Regards,

Hi,

Thx for your response. I downloaded and tried the latest version of aspose dlls as you pointed thru the url. That fixed the sample document you pointed out to but broke so many other cases. To illustrate it, I am attaching an example document “newConditionsFromScratch.docx” and the merged output “out_merged.dcox”. I get the following excpetion while calling doc.UpdateField call to update the if conditions values.(Please see the exception below). And I believe that is what messing up the results and not printing the right stuff after it gets the exception. I will greatly appreciate if you can look into this urgently and provide some sort of fix for me as I am stuck on this and there are many templates which are affected because of this. It seems to me that exception is only happening when the condition is inside a word table. Please see the template and output document where we have same conditions outside and inside the word table. Things work correctly and does not throw exception when outside the word table but throws the excetion on doc.UpdateFields() call when we have the if conditions inside the word table. Also it seems that it is only happening if I have all the IF conditions inside the word table. It does not happen if I remove the second broad if condition from the table. (Very intresting and puzzling).

Specified argument was out of the range of valid values.
Parameter name: text at x28925c9b27b37a46.x00b47748a95c9437.xcd4c71cf08e97198(
String xb41faee6912a2313)
at x2a6f63b6650e76c4.xe02d79c539b6382d.x1f490eac106aee12(Table x1ec770899c98a
268, String xc15bd84e01929885, Int32 x2238fe9b8f06bd9d)
at x2a6f63b6650e76c4.x393ce53fde4b6f6e.x1f490eac106aee12(Table x1ec770899c98a
268, String x2998bc0b2545c5b6, String xd58ddfc523d7f291)
at x2a6f63b6650e76c4.x393ce53fde4b6f6e.x19890931227f0f56(x12e7545fad3ccc9b x0
f7b23d1c393aed9, String xc15bd84e01929885, Boolean x87e8133a83e97e91, x209f3e4a2
f735d1e& x9b10ace6509508c0)
at x2a6f63b6650e76c4.x9322ca348f66fbd2.xf7bd47d7d4051da1(x12e7545fad3ccc9b x0
f7b23d1c393aed9, String x4e249dc4e99686bb, Boolean x87e8133a83e97e91)
at x2a6f63b6650e76c4.xd8780e89a96f3f1a.x9f7dc7131ed07aa4(String x137ffa3012d6
a67d)
at x2a6f63b6650e76c4.xd8780e89a96f3f1a.x095ca45783003376()
at x2a6f63b6650e76c4.xd8780e89a96f3f1a.x1f490eac106aee12()
at x2a6f63b6650e76c4.xd8780e89a96f3f1a.x1f490eac106aee12(x12e7545fad3ccc9b x0
f7b23d1c393aed9)
at x2a6f63b6650e76c4.x6d929209cd800011.x308cb2f3483de2a6(x12e7545fad3ccc9b x0
f7b23d1c393aed9)
at x2a6f63b6650e76c4.x6d929209cd800011.x308cb2f3483de2a6(Field xe01ae93d9fe5a
880, String xbf5efe8743edba7b)
at x2a6f63b6650e76c4.xa4690fb61715fc9b.x335c6a74b612cfe6(Field xe01ae93d9fe5a
880, x6f82c326b827643c xbf5efe8743edba7b)
at x2a6f63b6650e76c4.xa4690fb61715fc9b.x308cb2f3483de2a6(Field xe01ae93d9fe5a
880, x6f82c326b827643c xbf5efe8743edba7b)
at xfbd1009a0cbb9842.xedefa1db6f5ff538.x83bcdf1790545fdb()
at Aspose.Words.Fields.Field.x42a25ae95099edb8(x5e36356bc92c609b x0f7b23d1c39
3aed9)
at Aspose.Words.Fields.Field.x295cb4a1df7a5add(x5e36356bc92c609b x0f7b23d1c39
3aed9)
at xfbd1009a0cbb9842.xfedf115fd9c03862.x4e3cfc222c92cda7(Field xe01ae93d9fe5a
880, x5e36356bc92c609b x0f7b23d1c393aed9)
at xfbd1009a0cbb9842.xfedf115fd9c03862.x4e3cfc222c92cda7(Field xe01ae93d9fe5a
880)
at xfbd1009a0cbb9842.xbf9ddf72e1283af9.x18dfca7c5fd2402f()
at xfbd1009a0cbb9842.xfedf115fd9c03862.xdd6cf0348a23f220(xcf417e2db4fe9ed3 xe
00c282e1a49fcfb)
at xfbd1009a0cbb9842.xfedf115fd9c03862.x384c03e4298b53bf()
at Aspose.Words.Range.UpdateFields()
at Aspose.Words.Document.UpdateFields()
at WordDocMergeClient1.Program.Test5() in C:\Users\tverma\Documents\Visual St
udio 2008\Projects\WordDocMergeClient1\WordDocMergeClient1\Program.cs:line 720

Hi,

I hope someone is looking into this issue. Can you please provide some update on this or any suggested workarounds as this is a critical issue for us with some of the templates already in production use?

Thx

Thanmal.

Hi Thanmal,

Thanks for your inquiry and sorry for the delayed response.

I managed to reproduce this exception with the help of your code on my side. I have fixed the problematic fields (see the highlighted double quotes) in your Word template and attached a modified version (NewConditionFromScratch - Copy.docx) here for your reference. Please let us know how it goes on your side.

Best Regards,

Hi,

Thx for your reply. I see it working if I put an additional “” around the second IF condition inside the table as you highlighted. But I am more confused now. We have multi hundred templates where we use various combinations of IF conditions, sometime outside the table and sometime inside the table. If I understand the IF conditions correctly, I should not have to put the “” around the autotext field as you highlighted. Please correct me if I am wrong in my assumption. And it is practicaly impossible for me to go thru all these templates and start putting random double quotes around some IF conditions.

Furthermore, these same IF conditions are working fine outside the table perfectly. So, can you please explain me what is happing and why are you suggesting this fix as it does not make logical sense to me. I need to be able to define the rules in a logical way for our template writers as they are building new conditions every day.

It seems to me a defect in the Aspose code and if we agree than I would rather like to see a hotfix provided over the top of latest release so that these conditions work fine both inside and outside the table. I do not mind switiching to latest version even if it means a lot of testing on my side.

I will be more than willing to make the change to my templates as you suggested if it confirms to standard building of IF conditions. Otherwise believe me we will start finding so many different varioations that we will confuse ourselves as to where we put the doublequote and where we do not.

To me the standard IF condition building is : IF X = Y “TRUE values” “False Values”

And thats how we have build these conditions both inside and outside the table. These are working fine outside the table and when pasted inside the table it is breaking for some scenarios.

Please let me know your thoughts around it. I will appreciate a quicker turnaround on it. And as always thx in advance for all your help!

Thx

Thanmal.

Hi,

I hope you are looking into this and can provide some insight soon.

Thx

Thanmal.

Can someone please provide some update on this?

Thx

Thanmal.

Hi Thamal,

Thanks for your inquiry.

I managed to reproduce the issue on my side. It seems the exception occurs when the last Autotext in the document is given a field result with a particular string. If this string is a certain length and contains a number (such as the one you set) then the exception occurs during field update. This is a strange bug, I have logged this issue in our tracking system. We will inform you as soon as it is resolved.

For the time being the work around is what Awais has already found by adding extra speechmarks around that particular IF field

Also, note that at the moment Aspose.Words does not update AutoText fields, however in a future version it will. This will break the code that you use to manually set the AutoText field results. May I ask why you use AutoText fields in this way at all? Why not just use MergeFields?

Thanks,

Hi Adam,

Thx for your reply!

The reason we use Autotxet fields is that we have thousands of templates which were written 7-8 years back and thats what the system designer used way back when he designed the system. Of late, we have been using mergefields whereever possible, (Specially when we are creating dynamic tables, netsed tables etc.) but unfortunately have no choice currently to either change or discontinue the usage of Autotext fields. Also, in my past interactions with Aspose (over 3+ years) I was never told that this will not be supported in future or anything like that.

Currently after we merge these autotext fields and mergefields, I call doc.UpdateField() call from Aspose APIs to update the fields so that we can get the correct result.

Furthermore, to simplify our problems and help in communication with you, I was sending you a simplified sample template, but we have so many other cases that I really need a proper identification and fix of this issue so that IF conditions with autotext fields are handle in a well defined, consistent and reliable manners. Otherwsie it is near impossible to know when to put the additional quotes around the autotext field as you suggested. Now, if your diagnostics and analysis suggests that we can always reliably put quotes in all IF conditions where we use autotext fields, than that is something I can suggest as a norm going forward. but would need some assurances that it will not break up the feature in future releases. The reason being obviously that we just have so many templates that we can not keep chaning them randomly with every release of Aspose.

Also, I am not 100% sure, I understand your comments in regard to future Aspose release will break my code in temrs of creating autotect result fields etc. Can you please elaboarte more on it? Also please let me know the corrective action for that which will apply to current situation and future releases.

I sincerely hope, I am able to convey my use cases, problems and the reasoning behind my repeated request for proper diagnostics and fix of this issue. I can not stress how important and critical this issue is for us.

Please let me know if I need to provide more sample docs etc. to help you analyze more cases so that you can provide me with appropriate fixes.

Hope to hear back from you soon on this issue.

Thx

Thanmal.

Hi Thanmal,

Thanks for this additional information.

That’s understandable, quite a lot of customers have a large database full of documents from years ago so I can see why you need to use AUTOTEXT fields in this way. There maybe some confusion in my explanation on how your code may break in the future regarding these types of fields. Let me explain further:

  • An AUTOTEXT field is actually a dynamic field used to insert stored text or other content that is stored with a document.
  • Aspose.Words does fully support modifying any type of field in the document (like how you are doing in your code right now).
  • Currently Aspose.Words does not support the AUTOTEXT field in this version or any previous version. Therefore this field is skipped during field update which is why your modifications are left untouched during field update (doc.UpdateFields).
  • We are constantly adding support for all features in Aspose.Words, therefore in a future version we will support the AUTOTEXT field. What will happen then is this field will be updated during field update. Your custom field value will then be overridden with the true result of the AUTOTEXT field just like in the same way Microsoft Word updates the field. This will wipe the value you manually set in the field.
  • Note with your current output, if you open it in Microsoft Word and update fields (CTRL + A then F9) your AUTOTEXT fields are updated incorrectly and replaced with error messages. This is something to keep in mind when you distribute your output documents.

There are some possible solutions/ideas that could help with this issue:

  • You could use Aspose.Words to process once off all your templates and automatically convert AUTOTEXT fields into MERGEFIELD. Then you could use a standard merge function (Mail merge) instead of the extra code you are using now. If you use this technique it might just avoid many of the update problems you are having with your template.
  • You can use the following code Replace Fields with Static Text to convert AUTOTEXT fields to static text after you merge them with your data. This means the field engine will not touch these fields even when the AUTOTEXT field becomes supported.

If you are having any issues with field update with any your templates then you need to supply us with the documents and we will investigate and fix any issues that we find.

I would not suggest to add speechmarks around all IF fields in your documents. That is simply a possible work around for the time being.

Thanks,

Thx Adam for the excellent reply! Got busy with other things so could not reply earlier. Here are my followup questions:

  1. The reason people are using the Autotext field is for two reasons. One, it is easier to see if there is an issue after the merge. You just do the Alt + F8 and you can see the autotext fileds and if there is any merge issue, they can quickly see it. If we replace this with static text or mergefield, that mechanism is not possible. The other reason is that it allows us to re-merge an already merged document because the autotext fields are still there, we can find it and replace the values thru programming if the underlying data values have changed in DB and user wishes to remerge the already merged document. So my quetion to you is that is it possible to keep this feature while writing the autitext values in a different manner than waht we are doing currently, while merging so that current “Update filed” in MS Word or future Aspose chnages in regard to update field will not break this? This is very important for us to understand because it sets up our long term direction os soultions for all templates and autotext fileds. And may force us to give up on the philoshopy of remerging an already meged doc when the underlying field vaues are changed and instead always take the fresh template and run the merge.

  2. I will provide more concrete\realisitc exmplaes of current breaking templates so that you can suggest us the appropriate solutions for each case. I expect small numbers may be 5 identified so far. I will send this info to you in a day or two.

  3. I will also try out the mergefield approach on these problematic templates with various IF conditions and see if that takes away the issues. Will update you on the outcomes.

So, if possible, please reply to my 1st point and also let me know the outcome of your research on our existing issue reported so far on the autotext field and IF condition.

Thx

Thanmal.

Hi Thanmal,

Thanks for this additional information.

Regarding issue 1) if you use merge fields the technique to check for any left over fields is exactly the same, you can easily check if any are unmerged in the output document by pressing ALT+F9. You can even check this through code by using doc.MailMerge.GetFieldNames and checking if the length is greater than zero. Also note you can automatically choose to remove unmerged fields/empty paragraphs during mail merge by using the MailMergeCleanupOptions property.

You are correct that after mail merge the mergefields are removed and cannot be merged again. This functionality is out of the scope of a mergefield. However, as described in my previous post, using AUTOTEXT fields are not the answer either. If you really do not want to reload the document from sctratch and find you need to remerge some values, you may instead want to look into using bookmarks or form fields. Either of theses are a better options and will always work in Microsoft Word and in future versions of Aspose.Words. At the moment you cannot directly mail merge into a bookmark or form field but the Aspose.Words API allows you to easily work with book bookmarks and form fields. Let me know if you need any examples.

Please keep me informed about how you go with 2) and 3). We will be glad to help with any other queries you may have.

Thanks,

Hi Adam,

In regard to your previous response, is it possible to share some aspose api code which I can use to convert existing templates which are using autotext fields and use the code to convert the autotext fields to mergefields instead?

Thx in advance for your help!!

Thanmal.

Hi Thanmal,

Thanks for your inquiry and sorry for the delayed response. Sure, you can replace existing AUTOTEXT fields in your document with MERGEFIELDS by using the following code snippet:

Document doc = new Document(@"c:\temp\StaticTable_Aspose.docx");
DocumentBuilder builder = new DocumentBuilder(doc);
Node[] fieldStarts = doc.GetChildNodes(NodeType.FieldStart, true, false).ToArray();
foreach (FieldStart fieldStart in fieldStarts)
{
    if (fieldStart.FieldType == FieldType.FieldAutoText)
    {
        builder.MoveTo(fieldStart);
        string fieldCode = GetFieldCode(fieldStart).Trim();
        string fieldName = fieldCode.Split(new char[] { ' ' }, 2)[1];
        Node curNode = fieldStart;
        while (!(curNode.NodeType == NodeType.FieldEnd && ((FieldEnd)curNode).FieldType == FieldType.FieldAutoText))
        {
            curNode = curNode.NextPreOrder(fieldStart.Document);
        }
        RemoveSequence(fieldStart, curNode);
        builder.InsertField(" MERGEFIELD " + fieldName + " ");
        try
        {
            fieldStart.Remove();
            curNode.Remove();
        }
        catch { }
    }
}
doc.Save(@"c:\temp\out.docx");
private static string GetFieldCode(FieldStart fieldStart)
{
    StringBuilder builder = new StringBuilder();
    for (Node node = fieldStart; node != null && node.NodeType != NodeType.FieldSeparator &&
    node.NodeType != NodeType.FieldEnd; node = node.NextPreOrder(node.Document))
    {
        if (node.NodeType == NodeType.Run)
            builder.Append(node.GetText());
    }
    return builder.ToString();
}

private static void RemoveSequence(Node start, Node end)
{
    Node curNode = start.NextPreOrder(start.Document);
    while (curNode != null && !curNode.Equals(end))
    {
        Node nextNode = curNode.NextPreOrder(start.Document);
        if (curNode.IsComposite)
        {
            if (!(curNode as CompositeNode).ChildNodes.Contains(end) &&
            !(curNode as CompositeNode).ChildNodes.Contains(start))
            {
                nextNode = curNode.NextSibling;
                curNode.Remove();
            }
        }
        else
        {
            curNode.Remove();
        }
        curNode = nextNode;
    }
}

I hope, this will help.

Best Regards,

The issues you have found earlier (filed as WORDSNET-6187) have been fixed in this .NET update and this Java update.


This message was posted using Notification2Forum from Downloads module by aspose.notifier.