Wrong numbering about mail merge in ASPOSE.Word for .Net

I am using evaluation version of ASPOSE.Word for .Net version 9.5. However, I found the bullets and numbering are wrongly accumulate on next record. How to solve this problem? Eg. first record item number is from 1 to 12 and the second record is started from 13 to 24. Does it possible do not accumulate the numbering in the next record.

Hello

Thanks for your inquiry. Could you please attach your input and output documents here for testing? We will check the problem on my side and provide you more information.
Best regards,

I attached the Word file for your reference.

Hi Angus,
Thanks for your inquiry.
I managed to reproduce the issue on my side. I have logged a request to beable to handle how lists are numbered during mail merge with regions. We will keep you informed of any developments.
For now you can use the work around below: It sets up a handler which will restart the list numbering for each region during mail merge. You can use the code by setting up the handler before executing mail merge like below.

doc.MailMerge.FieldMergingCallback = new HandleListNumberingDuringMerge(doc);
doc.MailMerge.ExecuteWithRegions(dataSet);

///
/// Restarts list numbering within repeated regions that contain automatic list numbering.
///
public class HandleListNumberingDuringMerge: IFieldMergingCallback
{
    private RestartListsHandler mNodeHandler;
    private ArrayList mRegionNames;
    private int mCurrentRecord = -1;
    ///
    /// Restarts all lists encountered during mail merge. This should be normally used for simple mail merge.
    ///
    public HandleListNumberingDuringMerge(Document doc)
    {
        mNodeHandler = new RestartListsHandler();
        doc.NodeChangingCallback = mNodeHandler;
    }
    ///
    /// Restarts lists found in the regions only specified in the list. This is used for
    /// mail merge with regions.
    ///
    public HandleListNumberingDuringMerge(Document doc, ArrayList nameOfRegionsToRestart)
    {
        mNodeHandler = new RestartListsHandler();
        mRegionNames = nameOfRegionsToRestart;
        doc.NodeChangingCallback = mNodeHandler;
    }
    public void FieldMerging(FieldMergingArgs args)
    {
        // Is a field belonging to a region being merged.
        if (!string.IsNullOrEmpty(args.TableName))
        {
            // If this list is null we are processing all regions.
            if (mRegionNames != null)
            {
                // If the list does not contain this region name then skip restarting any lists in this region.
                if (!mRegionNames.Contains(args.TableName))
                    return;
            }
        }
        // A different record index means that a new region is being repeated. Clear the lists in the handler
        // so these lists will be separate from the last region.
        if (mCurrentRecord != args.RecordIndex)
        {
            mNodeHandler.ClearLists();
            mCurrentRecord = args.RecordIndex;
        }
    }
    public void ImageFieldMerging(ImageFieldMergingArgs args)
    {
        // Do Nothing.
    }
}
public class RestartListsHandler: INodeChangingCallback
{
    Dictionary <List, List> listLookup = new Dictionary <List, List> ();
    void INodeChangingCallback.NodeInserted(NodeChangingArgs args)
    {
        // Find any paragraphs inserted into the document and process them if they are list items.
        if (args.Node.IsComposite)
        {
            ArrayList paragraphs = new ArrayList();
            if (args.Node.NodeType != NodeType.Paragraph)
                paragraphs.AddRange(((CompositeNode) args.Node).GetChildNodes(NodeType.Paragraph, true).ToArray());
            else
                paragraphs.Add(args.Node);
            foreach(Paragraph para in paragraphs)
            {
                if (para.IsListItem)
                    RestartList(para);
            }
        }
    }
    ///
    /// Clears all the copied lists.
    ///
    public void ClearLists()
    {
        listLookup.Clear();
    }
    ///
    /// When you restart a list in MS Word it creates a whole new list and copies all formatting over. We do the
    /// same by copying over the list of the current paragraph. Store the new list so other paragraphs using the original list can be linked to this new one.
    ///
    private void RestartList(Paragraph para)
    {
        List newList = null;
        List paraList = para.ListFormat.List;
        // Check if there is already a copied list for this list
        if (listLookup.ContainsKey(paraList))
        {
            newList = listLookup[paraList];
        }
        else
        {
            // No copied list exists yet, make a new list copy.
            newList = para.Document.Lists.AddCopy(paraList);
            listLookup.Add(paraList, newList);
        }
        para.ListFormat.List = newList;
    }
    void INodeChangingCallback.NodeInserting(NodeChangingArgs args)
    {
        // Do Nothing
    }
    void INodeChangingCallback.NodeRemoved(NodeChangingArgs args)
    {
        // Do Nothing
    }
    void INodeChangingCallback.NodeRemoving(NodeChangingArgs args)
    {
        // Do Nothing
    }
}

Thanks,

Hi,
It is a good feature request and I agree sometimes it is needed to make list numbering to continue and sometimes to restart in mail merge regions. We are discussing a possible implementation of this feature now and most likely implement it soon.
In the meantime you can either try the workaround suggested by Adam above or just edit your document to avoid using numbered lists where you want the numbering to restart.
E.g. text “1. My text” which is a numbered list replace with simple manually entered list numbers “1. My text” I mean “1” followed by “.” followed by a tab character etc.

Hi aske012 ,
I followed your code to mail merge the letter. But the listing number is no difference. The code listing as following:

// <> *
// Open document
Document doc = new Document(tempDocFilePathName);
// Insert page break
// DocumentBuilder builder = new DocumentBuilder(doc);
DocumentBuilder builder = new DocumentBuilder(doc);
doc.MailMerge.FieldMergingCallback = new com.util.HandleListNumberingDuringMerge(doc);
// doc.MailMerge.ExecuteWithRegions(dataSet);
if (insertPageBreak)
{
    // Insert a page break before mail merge end region
    // Need to have a bookmark named pageBreak before the end field region in the template document
    builder.MoveToBookmark("pageBreak");
    builder.InsertBreak(BreakType.PageBreak);
}
// Execute the nested mail merge with regions
doc.MailMerge.ExecuteWithRegions(dt);
if (insertPageBreak)
{
    // Find the runs that contain the last page break characters in this section and remove the character.
    NodeCollection runs = doc.LastSection.GetChildNodes(NodeType.Run, true);
    for (int i = runs.Count - 1; i>= 0; i--)
    {
        Run run = (Run) runs[i];
        if (run.Text.IndexOf(ControlChar.PageBreakChar)>= 0)
        {
            run.Text = run.Text.Remove(run.Text.IndexOf(ControlChar.PageBreakChar), 1);
            break;
        }
    }
}
// Save the output to file
doc.Save(exportPDFfilePathName);
// <> *
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Aspose.Words;
using Aspose.Words.Reporting;
using Aspose.Words.Lists;
namespace com.util
{
    class LetterMailMerge
    {}
    ///
    /// Restarts list numbering within repeated regions that contain automatic list numbering.
    ///
    public class HandleListNumberingDuringMerge: IFieldMergingCallback
    {
        void IFieldMergingCallback.FieldMerging(FieldMergingArgs args)
        {
            // Do nothing.
        }
        private RestartListsHandler mNodeHandler;
        private int mCurrentRecord = -1;
        public HandleListNumberingDuringMerge(Document doc)
        {
            mNodeHandler = new RestartListsHandler();
            doc.NodeChangingCallback = mNodeHandler;
        }
        public void FieldMerging(FieldMergingArgs args)
        {
            // A different record index means that a new region is being repeated. Clear the lists in the handler
            // so these lists will be separate from the last region.
            if (mCurrentRecord != args.RecordIndex)
            {
                mNodeHandler.ClearLists();
                mCurrentRecord = args.RecordIndex;
            }
        }
        public void ImageFieldMerging(ImageFieldMergingArgs args)
        {
            // Do Nothing.
        }
    }
    public class RestartListsHandler: INodeChangingCallback
    {
        ///
        /// Stores a lookup between the original list of a paragraph and the new copy made for each repeated region.
        ///
        Dictionary <List, List> listLookup = new Dictionary <List, List> ();
        public RestartListsHandler()
        {
            listLookup = new Dictionary <List, List> ();
        }
        void INodeChangingCallback.NodeInserted(NodeChangingArgs args)
        {
            if (args.Node.NodeType == NodeType.Paragraph)
            {
                Paragraph para = (Paragraph) args.Node;
                if (para.IsListItem)
                {
                    RestartList(para);
                }
            }
        }
        ///
        /// Clears all the copied lists.
        ///
        public void ClearLists()
        {
            listLookup.Clear();
        }
        ///
        /// When you restart a list in MS Word it creates a whole new list and copies all formatting over. We do the
        /// same by copying over the list of the current paragraph. Store the new list so other paragraphs using the original list can be linked to this new one.
        ///
        private void RestartList(Paragraph para)
        {
            List newList = null;
            List paraList = para.ListFormat.List;
            // Check if there is already a copied list for this list
            if (listLookup.ContainsKey(paraList))
            {
                newList = listLookup[paraList];
            }
            else
            {
                // No copied list exists yet, make a new list copy.
                newList = para.Document.Lists.AddCopy(paraList);
                listLookup.Add(paraList, newList);
            }
            para.ListFormat.List = newList;
        }
        void INodeChangingCallback.NodeInserting(NodeChangingArgs args)
        {
            // Do Nothing
        }
        void INodeChangingCallback.NodeRemoved(NodeChangingArgs args)
        {
            // Do Nothing
        }
        void INodeChangingCallback.NodeRemoving(NodeChangingArgs args)
        {
            // Do Nothing
        }
    }
}

Hi Angus,
Thanks for your inquiry.
The code is not working because you have mistakenly added an explicit member implemenation of the FieldMerging interface which is being called instead of the proper implementation.
Please remove this empty method:

void IFieldMergingCallback.FieldMerging(FieldMergingArgs args)
while leaving this one in place:
    public void FieldMerging(FieldMergingArgs args)

The code should then work correctly.
Thanks,

Thanks! It’s work.

Does it possible this function works on execute mail merge without regions? The execute code seem like as following:

doc.MailMerge.FieldMergingCallback = new HandleListNumberingDuringMerge(doc);
doc.MailMerge.Execute(dataTable);

It is because after executed the mail merge with regions, the page number is accumulated. Which is not in my expectation. I need recount page number by every record and the following code is doesn’t work for it:

doc.FirstSection.PageSetup.RestartPageNumbering = true;

I attached the updated template for your reference.

Hi
Thank you for additional information. I wrote a small example of how you can use ExecuteWithRegions and reset the page number for the new sections. If you have any questions, feel free to ask.

namespace MailMergeExample
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var license = new License();
            license.SetLicense("Aspose.Words.lic");
            const string path = @"X:\";
            Document doc = new Document(path + "template.doc");
            doc.MailMerge.FieldMergingCallback = new HandleMerge(doc);
            doc.FirstSection.PageSetup.RestartPageNumbering = true;
            doc.MailMerge.ExecuteWithRegions(GetNamesDataTable());
            doc.Save(path + "out.doc", SaveFormat.Doc);
        }
        ///
        /// Create DataTable and fill it with data.
        /// In real life this DataTable should be filled from a database.
        ///
        private static DataTable GetNamesDataTable()
        {
            DataTable dataTable = new DataTable("Names");
            dataTable.Columns.Add("Name");
            for (int i = 0; i <10; i++)
            {
                DataRow datarow = dataTable.NewRow();
                dataTable.Rows.Add(datarow);
                datarow[0] = "name " + i;
            }
            return dataTable;
        }
    }
    internal class HandleMerge: IFieldMergingCallback
    {
        public HandleMerge(Document doc)
        {
            mDoc = doc;
        }
        public void FieldMerging(FieldMergingArgs args)
        {
            DocumentBuilder documentBuilder = new DocumentBuilder(mDoc);
            documentBuilder.MoveToField(args.Field, true);
            // Insert new section
            documentBuilder.InsertBreak(BreakType.SectionBreakNewPage);
        }
        public void ImageFieldMerging(ImageFieldMergingArgs args)
        {
            // Do nothing
        }
        private readonly Document mDoc;
    }
}

Thanks for reply my question.
I apply your code but it seem like add a page break in every field. I attached a file for your reference. Do you have any solution about mail merge without regions? It is because I do not need to add a start table tag and end table tag in the MS Word. No restriction with add a section break in the template. The template is made by the user. It is more simply works with mail merge without regions.
Angus Yu

Hi Angus,
Thanks for your inquiry.
Yes I see what you mean. The code should work for both situations but it appears the way the paragraphs are inserted during simple mail merge is a bit different to that of regions.
I have made a quick fix to the class so that both methods will be handled properly. Please make the specified changes in the RestartListsHandler class. Using this code you choose to use simple or mail merge with regions.

void INodeChangingCallback.NodeInserted(NodeChangingArgs args)
{
    // Find any paragraphs inserted into the document and process them if they are list items.
    if (args.Node.IsComposite)
    {
        ArrayList paragraphs = new ArrayList();
        if (args.Node.NodeType != NodeType.Paragraph)
            paragraphs.AddRange(((CompositeNode) args.Node).GetChildNodes(NodeType.Paragraph, true).ToArray());
        else
            paragraphs.Add(args.Node);
        foreach(Paragraph para in paragraphs)
        {
            if (para.IsListItem)
                RestartList(para);
        }
    }
}

Thank you Viktor for providing that sample code. Using Viktor’s code you can either choose to use simple mail merge or mail merge with regions for your document depending upon your specifications.
Thanks,

Thank you for additional information.
Sorry that I did not specify what I wanted to show by this code. I wanted to demonstrate how to manage the insertion of the section breaks. All you need is to insert a field at end of your template that will “signal” to our condition. Please see how I changed my template.
About the fact that the template creates by a user - you can do preprocessing and paste the field you needs programmatically.
Condition which must be added:

public void FieldMerging(FieldMergingArgs args)
{
    if (args.Field.Result == "½sectionBreakeField╗")
    {
        DocumentBuilder documentBuilder = new DocumentBuilder(mDoc);
        documentBuilder.MoveToField(args.Field, true);
        // Remove unnecessary field
        args.Field.Remove();
        // Insert new section
        documentBuilder.InsertBreak(BreakType.SectionBreakNewPage);
    }
}

Thanks and appreciate your effort.

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

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