Eliminate blank page

Hello:
I’m describing my scenario first. I’ve got a word template of two pages like this:
page-1
Dear Colleague «CustName»:
I’ve confirmed the invitation on the phone «Phone» ……………………
Hope all of you’ll join and enjoy the party.
With Regards-
Razin
page-2

Phone No List
«TableStart:Customer» «Phone» «TableEnd:Customer »

So, first i’d like to set max phone number suppose it’s 2 (it’s variable). Whenever any customer has got more that two phone numbers (suppose 5) the first two need to be displayes on the page-1 <> and the rest three need to be displayed on the page-2 as a list along with first two but If the customer has 2 or less than 2 phone numbers then the second page needs to be eliminated for that customer. These template will generate several customers invitation.
I’ve created a data table and executed this command
doc.MailMerge.Execute(dtCustomer); - dtCustomer: DataTable name
So, my template is generating along with all the selected cutomers but I need to how can I solve the above case.
I need you urgent help. I’ll be benefited if u provide me some source.
Thanks-
Razin

Hi
Thanks for your interest in Aspose.Words. I think that the following code will be useful for you. Also see attached template.

DataTable customer = new DataTable("Customer");
customer.Columns.Add("Phone");
for (int i = 0; i < 2; i++)
{
    DataRow row = customer.NewRow();
    row[0] = "564654654654";
    customer.Rows.Add(row);
}
//open template
Document doc = new Document(@"371_103385_thk_razin\in.doc");
//create short phonelist
DataTable phones = new DataTable("Phones");
phones.Columns.Add("Phone");
if (customer.Rows.Count > 2)
{
    for (int i = 0; i < 2; i++)
    {
        DataRow row = phones.NewRow();
        row[0] = customer.Rows[0][0].ToString();
        phones.Rows.Add(row);
    }
    //merge 2nd page
    doc.MailMerge.ExecuteWithRegions(customer);
}
else
{
    foreach (DataRow cusRow in customer.Rows)
    {
        DataRow row = phones.NewRow();
        row[0] = cusRow[0].ToString();
        phones.Rows.Add(row);
    }
    //remove second page.
    DocumentBuilder builder = new DocumentBuilder(doc);
    builder.MoveToMergeField("Customer");
    builder.CurrentSection.Remove();
}
doc.MailMerge.ExecuteWithRegions(phones);
//save document
doc.Save(@"371_103385_thk_razin\out.doc");

I hope that this will help you.
Best regards.

Hi:
Thanks for your response. It’s gonna help me, surely. I’ve got a question. In the first page I don’t need any table like this

«TableStart:Phones»«Phone»«TableEnd:Phones»

cause all those merge fields are single value. I said i’ve a series of phone number. 22333, 243333, 22222 etc. but this is actually a string value. If the max length is 2. I’ll place 22333, 243333 in the first page and all the three no in the second page (which contains a table)
You’ve used two table cause u’ve used a loop to generate all those phone nmbers but my phone number list will directly come from from database so i don’t need a table for the first page.
So is it possible to use
doc.MailMerge.ExecuteWithRegions(phones); //phones - DataTable name, which contains Phone List
and
doc.MailMerge.Execute(dtCustomer); //dtCustomer - DataTable name, which contains customer name, Address, Phone numbers etc.
in the same document…???
And the field name <> should be different for first and second page…???
I need further help.
Thanx
Razin

Hi
Thanks for your explanation.
Yes, I think that you can use Execute and ExecuteWithRegions Methods in the same document.
You can use same names of fields in the region and outside region.
See the following code. Also see attached template.

DataTable customer = new DataTable("Customer");
customer.Columns.Add("CustName");
customer.Columns.Add("Phone");
DataRow row = customer.NewRow();
row[0] = "test";
row[1] = "1233445,2783946,545654494,45646546565";
customer.Rows.Add(row);
//open template
Document doc = new Document(@"371_103385_thk_razin\in.doc");
string[] phoneArr = customer.Rows[0]["Phone"].ToString().Split(',');
if (phoneArr.Length > 2)
{
    //create short phonelist
    DataTable phones = new DataTable("CustomerPhones");
    phones.Columns.Add("Phone");
    for (int i = 0; i < phoneArr.Length; i++)
    {
        DataRow phoneRow = phones.NewRow();
        phoneRow[0] = phoneArr[i];
        phones.Rows.Add(phoneRow);
    }
    doc.MailMerge.ExecuteWithRegions(phones);
}
else
{
    DocumentBuilder builder = new DocumentBuilder(doc);
    builder.MoveToMergeField("CustomerPhones");
    builder.CurrentSection.Remove();
}
doc.MailMerge.Execute(customer);
//save document
doc.Save(@"371_103385_thk_razin\out.doc");

I hope that this will help you.
Best regards.

Hi:
Thank you very much for your comments and code. That will help me a lot. I think my problem is solved. if I face further problem i’ll knock u again.
Thanks again-
Razin

Hi:
I’ve got another problem. The example u’ve provided is applicable for a single customer. But I have multiple customers. So, I’ve to create multiple phone list and have to eliminate multiple pages where there is no phone list. Another thing

if (phoneArr.Length > 2)
{
}

if phone numbers are more than 2 then the first two comes in the first page (not all of those).
I’ve got problem ‘Object reference not set to an instance of an object’
It occurs cause i’m trying to eliminate second page several times.
I need help.
Thanx-
Razin

Hi:
My problem is more like this:

DataTable customer = new DataTable("Customer");
customer.Columns.Add("CustName");
customer.Columns.Add("Phone");
DataRow row = customer.NewRow();
row[0] = "test11111";
row[1] = "1233445,2783946,545654494,45646546565";
customer.Rows.Add(row);
DataRow row1 = customer.NewRow();
row1[0] = "test22222";
row1[1] = "5233445,7783946";

-----Max Value 2--------
for the first row 1233445,2783946 this two numbers should appear on the first page and all of those 4 numbers appears on the second page but for the second row there is only two numbers so those should appear on the third page and fourth page(List page) will be eliminated.
Thnx-
Razin

Hi
Thank you for additional information. I think that a solution for you is building up a resulting document from several documents. You should use two templates. See the following code. Templates are attached.

public void TestMailMerge_103385()
{
    DataTable customer = new DataTable("Customer");
    customer.Columns.Add("CustName");
    customer.Columns.Add("Phone");
    DataRow row = customer.NewRow();
    row[0] = "test1111";
    row[1] = "1233445,2783946,545654494,45646546565";
    customer.Rows.Add(row);
    DataRow row1 = customer.NewRow();
    row1[0] = "test22222";
    row1[1] = "5233445,7783946";
    customer.Rows.Add(row1);
    DataRow row2 = customer.NewRow();
    row2[0] = "test3333";
    row2[1] = "1233445,2783946,545654494,45646546565";
    customer.Rows.Add(row2);
    //open template
    Document doc = new Document(@"371_103385_thk_razin\in1.doc");
    doc.MailMerge.MergeField += new MergeFieldEventHandler(MailMerge_MergeField_103385);
    doc.MailMerge.Execute(customer);
    //save document
    doc.Save(@"371_103385_thk_razin\out.doc");
}
void MailMerge_MergeField_103385(object sender, MergeFieldEventArgs e)
{
    if (e.FieldName == "Phone")
    {
        DocumentBuilder builder = new DocumentBuilder(e.Document);
        builder.MoveToMergeField("PhoneList");
        string[] phoneArr = e.FieldValue.ToString().Split(',');
        if (phoneArr.Length > 2)
        {
            e.Text = string.Format("{0},{1}", phoneArr[0], phoneArr[1]);
            //create short phonelist
            DataTable phones = new DataTable("CustomerPhones");
            phones.Columns.Add("Phone");
            for (int i = 0; i < phoneArr.Length; i++)
            {
                DataRow phoneRow = phones.NewRow();
                phoneRow[0] = phoneArr[i];
                phones.Rows.Add(phoneRow);
            }
            Document doc2 = new Document(@"371_103385_thk_razin\in2.doc");
            doc2.MailMerge.ExecuteWithRegions(phones);
            builder.InsertBreak(BreakType.PageBreak);
            InsertDocument(builder.CurrentParagraph, doc2);
        }
    }
}

InserDocument method you can find here.
https://docs.aspose.com/words/net/insert-and-append-documents/
I hope that it will help you.
Best regards.

Hi:
Thanks for your response. Great. It’s doing exactly what I wanted. But my problem is i’m not getting this template from any disk rather i inserted it(whole document) into database (Oracle). I mapped all the template variable once(at the very beginning) and want to execute (fields are coming from different tables). So, I need to do the same thing (ouput is perfect) u sent but I can’t saperate the document. Is there any other option. I need ur help.
Sorry I didn’t tell my exact scenario before.
Thanx-
Razin

Hi
You should replace the following line

Document doc = new Document(@"371_103385_thk_razin\in1.doc");

With

Document doc = new Document(@"371_103385_thk_razin\in.doc");
doc.Sections[1].Remove();

and the following

Document doc2 = new Document(@"371_103385_thk_razin\in2.doc");

With

Document doc2 = new Document(@"371_103385_thk_razin\in.doc");
doc2.Sections[0].Remove();

Also see attached template.
Best regards.

Hello:
I’ve tried your new document file and code but the output is not generating properly. This is the modified code:

private void MyMethod()
{
    DataTable customer = new DataTable("Customer");
    customer.Columns.Add("CustName");
    customer.Columns.Add("Phone");
    DataRow row = customer.NewRow();
    row[0] = "test1111";
    row[1] = "991233445,992783946,99545654494,9945646546565,9945646546565";
    customer.Rows.Add(row);
    DataRow row1 = customer.NewRow();
    row1[0] = "test22222";
    row1[1] = "5233445,7783946";
    customer.Rows.Add(row1);
    DataRow row2 = customer.NewRow();
    row2[0] = "test3333";
    row2[1] = "551233445,552783946,55545654494,55545646546565";
    customer.Rows.Add(row2);
    //open template
    //Document doc = new Document("C:\\Inetpub\\wwwroot\\AsposeTest\\Documents\\in1.doc");
    Document doc = new Document("C:\\Inetpub\\wwwroot\\AsposeTest\\Documents\\inMy.doc");
    doc.Sections[1].Remove();
    doc.MailMerge.MergeField += new MergeFieldEventHandler(MailMerge_MergeField_103385);
    doc.MailMerge.Execute(customer);
    //save document
    doc.Save("C:\\Inetpub\\wwwroot\\AsposeTest\\Documents\\outMy.doc");
}
//--------------------------------------------------------------------
void MailMerge_MergeField_103385(object sender, MergeFieldEventArgs e)
{
    if (e.FieldName == "Phone")
    {
        DocumentBuilder builder = new DocumentBuilder(e.Document);
        builder.MoveToMergeField("PhoneList");
        string[] phoneArr = e.FieldValue.ToString().Split(',');
        if (phoneArr.Length > 2)
        {
            e.Text = string.Format("{0},{1}", phoneArr[0], phoneArr[1]);
            //create short phonelist
            DataTable phones = new DataTable("Customer");
            phones.Columns.Add("Phone");
            for (int i = 0; i < phoneArr.Length; i++)
            {
                DataRow phoneRow = phones.NewRow();
                phoneRow[0] = phoneArr[i];
                phones.Rows.Add(phoneRow);
            }
            //Document doc2 = new Document("C:\\Inetpub\\wwwroot\\AsposeTest\\Documents\\in2.doc");
            Document doc2 = new Document("C:\\Inetpub\\wwwroot\\AsposeTest\\Documents\\inMy.doc");
            doc2.Sections[0].Remove();
            doc2.MailMerge.ExecuteWithRegions(phones);
            builder.InsertBreak(BreakType.PageBreak);
            InsertDocument(builder.CurrentParagraph, doc2);
        }
    }
}
//--------------------------------------------------------------------
public void InsertDocument(Node insertAfterNode, Document srcDoc)
{
    // We need to make sure that the specified node is either pargraph or table.
    if (!((insertAfterNode.NodeType == NodeType.Paragraph) ||
    (insertAfterNode.NodeType == NodeType.Table)))
        throw new ArgumentException("The destination node should be either paragraph or table.");
    // We will be inserting into the parent of the destination paragraph.
    CompositeNode dstStory = insertAfterNode.ParentNode;
    // This object will be translating styles and lists during the import.
    NodeImporter importer = new NodeImporter(srcDoc, insertAfterNode.Document,
    ImportFormatMode.KeepSourceFormatting);
    // Loop through all sections in the source document.
    foreach (Section srcSection in srcDoc.Sections)
    {
        // Loop through all block level nodes (paragraphs and tables) in the body of the section.
        foreach (Node srcNode in srcSection.Body)
        {
            // Do not insert node if it is a last empty paragarph in the section.
            Paragraph para = srcNode as Paragraph;
            if ((para != null) && para.IsEndOfSection && !para.HasChildNodes)
                break;
            // This creates a clone of the node, suitable for insertion into the destination document.
            Node newNode = importer.ImportNode(srcNode, true);
            // Insert new node after the reference node.
            dstStory.InsertAfter(newNode, insertAfterNode);
            insertAfterNode = newNode;
        }
    }
}

The input and output files are attached. please see the attacment. My desired output is exactly you done using two separate files. I’m in big trouble.
Need your help.
Thanx-
Razin

Hi
Thank you for additional information. Here is code that will work fine.

public void TestMailMerge_103385()
{
    DataTable customer = new DataTable("Customer");
    customer.Columns.Add("CustName");
    customer.Columns.Add("Phone");
    DataRow row = customer.NewRow();
    row[0] = "test1111";
    row[1] = "991233445,992783946,99545654494,9945646546565,9945646546565";
    customer.Rows.Add(row);
    DataRow row1 = customer.NewRow();
    row1[0] = "test22222";
    row1[1] = "5233445,7783946";
    customer.Rows.Add(row1);
    DataRow row2 = customer.NewRow();
    row2[0] = "test3333";
    row2[1] = "551233445,552783946,55545654494,55545646546565";
    customer.Rows.Add(row2);
    //open template
    Document doc = new Document(@"263_103385_thk_razin\inMy.doc");
    doc.Sections[1].Remove();
    doc.MailMerge.MergeField += new MergeFieldEventHandler(MailMerge_MergeField_103385);
    doc.MailMerge.Execute(customer);
    //save document
    doc.Save(@"263_103385_thk_razin\out.doc");
}
void MailMerge_MergeField_103385(object sender, MergeFieldEventArgs e)
{
    if (e.FieldName == "Phone")
    {
        DocumentBuilder builder = new DocumentBuilder(e.Document);
        builder.MoveToMergeField("PhoneList");
        string[] phoneArr = e.FieldValue.ToString().Split(',');
        if (phoneArr.Length > 2)
        {
            e.Text = string.Format("{0},{1}", phoneArr[0], phoneArr[1]);
            //create short phonelist
            DataTable phones = new DataTable("CustomerPhones");
            phones.Columns.Add("Phone");
            for (int i = 0; i < phoneArr.Length; i++)
            {
                DataRow phoneRow = phones.NewRow();
                phoneRow[0] = phoneArr[i];
                phones.Rows.Add(phoneRow);
            }
            Document doc2 = new Document(@"263_103385_thk_razin\inMy.doc");
            doc2.Sections[0].Remove();
            doc2.MailMerge.ExecuteWithRegions(phones);
            builder.InsertBreak(BreakType.PageBreak);
            InsertDocument(builder.CurrentParagraph, doc2);
        }
    }
}

Best regards.

Hi:
Thanks for your response. Your code is working fine. But whenever i’m trying to incorporate it in my code it causes a problem (document generates but not properly). Here i’m explaining my code:

private void GenerateLetter()
{
    DataTable dtCustomer = new DataTable("Customer");
    string currentObject = "";
    if (docGenDocumentArchive != null) //It's a class by which i'm fetching the document from database
    {
        MemoryStream ms = new MemoryStream(docGenDocumentArchive.Document);
        doc = new Document(ms);
        doc.Sections[1].Remove(); //Removing Section 1
    }
    foreach (DocGenDocumentDetailsArchive objDocGenDocumentDetailsArchive in docGenDocumentDetailsArchiveCol)
    { ///DocGenDocumentDetailsArchive : By this class i've fetched all the document variables assigned 
        dtCustomer.Columns.Add(new DataColumn(objDocGenDocumentDetailsArchive.TemplateVariableName));
    }
    int rNo = 0;
    DataRow dr = null;
    foreach (DocGenCustomerDetailInformation docGenCustomerDetailInformation in objDocGenCustomerDetailInformation)
    {
        dr = dtCustomer.NewRow();
        foreach (DocGenDocumentDetailsArchive objDocGenDocumentDetailsArchive in docGenDocumentDetailsArchiveCol)
        {
            currentObject = objDocGenDocumentDetailsArchive.SystemObjectProperty;
            int remPart = currentObject.LastIndexOf(".");
            currentObject = currentObject.Remove(0, remPart + 1);
            customerProps = docGenCustomerDetailInformation.GetType().GetProperties();
            foreach (PropertyInfo customerProp in customerProps)
            {
                if ((customerProp.Name.ToLower() == currentObject.ToLower()) && (dtCustomer.Columns.Count > rNo))
                {
                    if (objDocGenDocumentDetailsArchive.AdvanceOption == "1")
                    {
                        doc.MailMerge.MergeField += new MergeFieldEventHandler(MailMerge_MergeField_103385);
                        dr[rNo] = customerProp.GetValue(docGenCustomerDetailInformation, null).ToString();
                    }
                }
                rNo++;
            }
            dtCustomer.Rows.Add(dr);
            rNo = 0;
        }
        doc.MailMerge.Execute(dtCustomer);
    }
    void MailMerge_MergeField_103385(object sender, MergeFieldEventArgs e)
    {
        ///Exactly what u've done
    }
    public void InsertDocument(Node insertAfterNode, Document srcDoc)
    {
        ///Exactly what u've done
    }
}

I’ve attached the output and code detail so that u can understand my problem. I’ve marked the problems on the output document.
Problems of the output :

  1. Blank first page
  2. List appears on the first page

Thanks-
Razin

Hi
I think that your code should looks like the following.

private void GenerateLetter()
{
    DataTable dtCustomer = new DataTable("Customer");
    string currentObject = "";
    foreach (DocGenDocumentDetailsArchive objDocGenDocumentDetailsArchive in docGenDocumentDetailsArchiveCol)
    { ///DocGenDocumentDetailsArchive : By this class i've fetched all the document variables assigned 
        dtCustomer.Columns.Add(new DataColumn(objDocGenDocumentDetailsArchive.TemplateVariableName));
    }
    int rNo = 0;
    DataRow dr = null;
    foreach (DocGenCustomerDetailInformation docGenCustomerDetailInformation in objDocGenCustomerDetailInformation)
    {
        dr = dtCustomer.NewRow();
        foreach (DocGenDocumentDetailsArchive objDocGenDocumentDetailsArchive in docGenDocumentDetailsArchiveCol)
        {
            currentObject = objDocGenDocumentDetailsArchive.SystemObjectProperty;
            int remPart = currentObject.LastIndexOf(".");
            currentObject = currentObject.Remove(0, remPart + 1);
            customerProps = docGenCustomerDetailInformation.GetType().GetProperties();
            foreach (PropertyInfo customerProp in customerProps)
            {
                if ((customerProp.Name.ToLower() == currentObject.ToLower()) && (dtCustomer.Columns.Count > rNo))
                {
                    if (objDocGenDocumentDetailsArchive.AdvanceOption == "1")
                    {
                        dr[rNo] = customerProp.GetValue(docGenCustomerDetailInformation, null).ToString();
                    }
                }
                rNo++;
            }
            dtCustomer.Rows.Add(dr);
            rNo = 0;
        }
    }
    if (docGenDocumentArchive != null) //It's a class by which i'm fetching the document from database
    {
        MemoryStream ms = new MemoryStream(docGenDocumentArchive.Document);
        doc = new Document(ms);
        doc.Sections[1].Remove(); //Removing Section 1
        doc.MailMerge.MergeField += new MergeFieldEventHandler(MailMerge_MergeField_103385);
        doc.MailMerge.Execute(dtCustomer);
    }
}

I hope that this will help you.
Best regards.

Hi:
Thanks very much. It’s working fine. I’ve to ask an additional thing. U’ve used a merge filed named
«PhoneList». Is it possible to create it during run time? Cause If I ask users to create it they might create it with a different name or might make spelling mistake !!!
Thanks again for your long support.
Razin

Hi
Thanks for this inquiry. Yes you can create mergefield during run time. See the following code for example

Document doc = new Document(@"371_103385_thk_razin\in.doc");
doc.Sections[1].Remove();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveToDocumentEnd();
builder.InsertField(@"MERGEFIELD PhoneList \* MERGEFORMAT", "«PhoneList»");
doc.MailMerge.MergeField += new MergeFieldEventHandler(MailMerge_MergeField_103385);
doc.MailMerge.Execute(customer);

Best regards.

Hi Alex:
Thanks boss. It’s fine. I’ve another question? Is it possible to find the table name of a document…?? Surely there is only one table in that document.
What I’ve done is placed a key in the web config:

<add key="ListTableName" value="CustomerPhones"/>

Then get the key from page:

string shortPhoneList = System.Configuration.ConfigurationManager.AppSettings["ListTableName"]; 
DataTable phones = new DataTable(shortPhoneList); 

If it’s possible to get the table name of a document during run time, i don’t need to do it.
Thanks again-
Razin

Hi
Thanks for inquiry. Yes, you can get regions names. You can try using the following code.

Document doc = new Document(@"405_103385_thk_razin\in.doc");
string[] names = doc.MailMerge.GetFieldNames();
ArrayList tablesList = new ArrayList(); //list of regions names.
for (int i = 0; i < names.Length; i++)
{
    if (names[i].ToLower().StartsWith("tablestart:"))
    {
        tablesList.Add(names[i].Substring(names[i].IndexOf(":") + 1));
    }
}

I hope that this will help you.
Best regards.

Hi:
Thanks very much.
Razin