Insert docs from DataSet to report doc

Here is a code to insert image from datset into document reports, In the same context, we want to replace image by word documents .
for example (product.doc instead of product.gif)

public Document MailMergeImageFileName()
{
    //This example loads Product table from an XML file.
    DataSet ds = new DataSet();
    //ds.ReadXml(gBasePath + "InsertionXML.xml");
    //ds.ReadXml(Server.MapPath("InsertionXML.xml"));
    string a = Server.MapPath("") + "\\" + "Insertion.xml";
    ds.ReadXml(a);
    //Open the report template document.
    Document doc = new Document(Server.MapPath("") + "\\Documents\\MailMergeImageFileName.doc");
    // doc = new Document(gBasePath + "MailMergeImageFileName.doc");
    //Attach an event handler that will be called for the Image:ProductImage merge field.
    doc.MailMerge.MergeImageField += new MergeImageFieldEventHandler(HandleMergeImageField);
    //Invoke mail merge. Note we are using merge regions because we want the table in the document to grow.
    doc.MailMerge.ExecuteWithRegions(ds.Tables["Product"]);
    //doc.Save(gBasePath + "MailMergeImageFileName Out.doc");
    return doc;
}// This is an event handler that gets called for every record for any Image:xxx merge field in the document.
    //*********************************************************************************************
private void HandleMergeImageField(object sender, MergeImageFieldEventArgs e)
{
    if (e.FieldName == "ProductImage")
    {
        //FieldValue contains just the value from the database - it's the short image file name.
        string fileName = (string)e.FieldValue;
        //Our task is to create a complete image file name with its path and let the mail merge
        //engine continue, it will load the image and insert it into the document.
        e.ImageFileName = Server.MapPath("") + "\\" + fileName;
    }
}

Here is the XML file that contents the data.

<Products>
	<Product>
		<ProductCode>
			<h1>123</h1>
		</ProductCode>
		<ProductImage>Product123.gif</ProductImage>
	</Product>
	<Product>
		<ProductCode>1011</ProductCode>
		<ProductImage>positions.gif</ProductImage>
	</Product>
</Products>

If we want to replace image by word documents, How can we proced to rewrite HandleMergeImageField to HandleMergeDocField?

private void HandleMergeDocField(object sender, MergeImageFieldEventArgs e)
{
    if (e.FieldName == "ProductImage")
    {
        //FieldValue contains just the value from the database - it's the short image file name.
        string fileName = (string)e.FieldValue;
        //Our task is to create a complete image file name with its path and let the mail merge
        //engine continue, it will load the image and insert it into the document.
        e.ImageFileName = Server.MapPath("") + "\\" + fileName;
    }
}

for example my XML doc becomes (.doc instead of .gif)

 <Products>
	<Product>
		<ProductCode>
			<h1>livre</h1>
		</ProductCode>
		<ProductImage>livre.doc</ProductImage>
	</Product>
	<Product>
		<ProductCode>catalogue</ProductCode>
		<ProductImage>catalogue.doc</ProductImage>
	</Product>
</Products>

Please help !!!

I don’t think that this code is intended for those purposes. But why do you consider this solution unsuitable:

https://forum.aspose.com/t/128786?

Load your XML into the dataset and change the MergeFieldEventHandler like this:

static void MailMerge_MergeField(object sender, MergeFieldEventArgs e)
{
    if (e.FieldName == "ProductImage")
    {
        string fileName = Server.MapPath("") + "" + (string)e.FieldValue;
        Document doc = new Document(fileName);
        AppendDoc(e.Document, doc);
    }
}

https://forum.aspose.com/t/128786?

Thank you,
that solution is unsuitable bacause it does not solve our problem.

It only insert this two words :PREPBETREVORGCONS and PREPLAVAGEHP in our report doc (that we don’t want).
we want to insert the document PREPBETREVORGCONS.doc in report doc.
and PREPLAVAGEHP.doc in the report doc, etc…

in our database table we’ve :

Title document
Préparation des supports PREPBETREVORGCONS.doc
Travaux préparatoires PREPLAVAGEHP.doc

where PREPBETREVORGCONS.doc and PREPLAVAGEHP.doc are stored in folder.

Please help us.

We are sorry, but we can only repeat that the solution should work perfectly. The only thing you should do is adapting the event handler for your needs. Debug the application, check that the documents are opened properly. Correct the path to the documents that is constructed in the event handler. Remove the line containing File.Exists method, then if the documents are not found, an exception will be thrown.

Thank you for your reply!

You’ve not undertood my question.

The solution you showed me works perfectly But it is not doing what we want.

Regards

I meant that the solution would completely meet your requirements if you modify it a little in accordance with your database schema and your project in general.

Okay, let’s try to resolve it nevertheless.

If you want to put your documents into resulting report one by one, according to the order in the data table:

Thus your data table looks like this:

Title document
Préparation des supports PREPBETREVORGCONS.doc
Travaux préparatoires PREPLAVAGEHP.doc
  1. Create appropriate merge field in the destination document.
  2. Pass DataTable to the DoMerge method:
void DoMerge(DataTable table)
{
    // Open template document
    Document doc = new Document(“template.doc”);
    // Attach the event handler to the MergeField event
    doc.MailMerge.MergeField +=
    new MergeFieldEventHandler(MailMerge_MergeField);
    // Execute mail merge with regions
    doc.MailMerge.ExecuteWithRegions(table);
    // Save the resulting document
    doc.Save(“result.doc”);
}

void AppendDoc(Document dstDoc, Document srcDoc)
{
    while (srcDoc.Sections.Count > 0)
    {
        // Obtain a section from source document
        Section section = srcDoc.Sections[0];
        // Remove the section
        srcDoc.Sections.RemoveAt(0);
        // Add the section to the source document
        dstDoc.Sections.Add(section);
    }
}

void MailMerge_MergeField(object sender, MergeFieldEventArgs e)
{
    // PLEASE HAVE A LOOK AT THIS LINE. THIS IS THE PATH TO YOUR SOURCE
    // DOCUMENTS. REPLACE IT WITH APPROPRIATE PATH IF NEEDED.
    string path = “D:”;
    // Obtain document file name from the data table
    string fileName = System.IO.Path.Combine(path,
    e.FieldValue.ToString());
    // Open this document
    Document doc = new Document(fileName);
    // Copy the document section by section
    AppendDoc(e.Document, doc);
    // Say the mail merge engine to remove the merge field
    e.Text = String.Empty;
}

If use of the database is not necessary, you can do following:

  1. Place bookmarks into the destination document. Give each bookmark name of the document you want to replace the bookmark with, but exclude “doc” extension (e.g. if you want to replace a bookmark with PREPLAVAGEHP.doc, name it PREPLAVAGEHP).

  2. Call the DoMerge method:

void DoMerge()
{
    // PLEASE HAVE A LOOK AT THIS LINE. THIS IS THE PATH TO YOUR SOURCE
    // DOCUMENTS. REPLACE IT WITH APPROPRIATE PATH IF NEEDED.
    string path = “”;
    // Open template document
    Document doc = new Document(“template.doc”);
    // Create a document builder
    DocumentBuilder builder = new DocumentBuilder(doc);
    foreach (Bookmark bookmark in doc.Range.Bookmarks)
    {
        // Move to a bookmark
        builder.MoveToBookmark(bookmark.Name);
        // Form a document file name
        string fileName = System.IO.Path.Combine(path,
        bookmark.Name + “.doc”);
        // Open source document
        Document sourceDoc = new Document(fileName);
        // Copy the document section by section
        AppendDoc(doc, sourceDoc);
    }
    doc.Save(“result.doc”);
}

void AppendDoc(Document dstDoc, Document srcDoc)
{
    while (srcDoc.Sections.Count > 0)
    {
        // Obtain a section from source document
        Section section = srcDoc.Sections[0];
        // Remove the section
        srcDoc.Sections.RemoveAt(0);
        // Add the section to the source document
        dstDoc.Sections.Add(section);
    }
}

Thank you for your help!
Instead of inserting documents to mailmerge field, it Append documents at the end of the template doc. And each document is added at a new page.

I tried to resolve this but nothing.

I send you the template and results.

Any help will be appreciated !!!

Here is result.doc

In your document the merge fields are located in the middle of the text. Unfortunately, there is no method allowing to insert sections exactly at merge field, all the existent methods append/prepend a section or its content to another section. But we are going to implement such the method soon, possibly this month.

Thank you,
Let us know availability of those methods.

Hi,
is this methods available ?

Hi,

Sorry, no progress yet. Please check back later.

Hello,
We contact you to know if this method is yet available ?

if not, will it be implemented later ?

Regards

Hi,

Unfortunately, no luck yet, but it has high priority among other features to implement.

Hi, previous post is a while back now, so I assume that by now there would be a good chance that the method was implemented in one of the latest releases? We are looking for the exact same thing, a solution which would allow us to insert section(s) derived from another document at the locaction of the mergefield.
Currently I’ve only found examples that show how to append sections at the end of a document. An alternative solution I guess would to find out what section the mergefield is located in and then build a new document containing all the sections up until that point, then use append section, then add the rest of the sections of the main document. Problem: just how do I find out what section a merge field is in?.
Many Thanks
Fred

Yes, that is possible to do with the current API. Here is a complete example.

private void MailMergeDocument()
{
    // Open the document.
    string filename = Application.StartupPath + @"\Doc1.doc";
    Document doc = new Document(filename);
    // add a hadler to MergeField event
    doc.MailMerge.MergeField += new MergeFieldEventHandler(MergeFieldHandler1);
    // Our document has merge field in it called MergeDoc2.
    // The corresponding data for this field contains fully qualified path to the document that should be inserted to this field.
    doc.MailMerge.Execute(new string[] { "MergeDoc2" }, new string[] { Application.StartupPath + @"\doc2.doc" });
    // save resulting document with a new name
    doc.Save(System.IO.Path.GetFileNameWithoutExtension(filename) + "_modified.doc");
}
private void MergeFieldHandler1(object sender, MergeFieldEventArgs e)
{
    // This handler makes special processing for the fields starting with "MergeDoc" prefix.
    // It treats field value as a document path,
    // opens the document at this path
    // and inserts the contents of the document in the field position.
    if (e.DocumentFieldName.StartsWith("MergeDoc"))
    {
        DocumentBuilder builder = new DocumentBuilder(e.Document);
        builder.MoveToMergeField(e.DocumentFieldName);
        InsertDocument(builder.CurrentParagraph, new Document((string)e.FieldValue));
        e.Text = "";
    }
}
public void InsertDocument(Node node, Document doc)
{
    Document dstDoc = node.Document;
    Section insertedSection;
    int index;
    if (node.GetAncestor(typeof(Cell)) != null || node.GetAncestor(typeof(Shape)) != null)
    {
        // Insertion point is tracked to Cell or Shape level:
        // - insert appended document on node by node basis.
        index = node.ParentNode.ChildNodes.IndexOf(node);
        foreach (Section section in doc.Sections)
        {
            insertedSection = (Section)dstDoc.ImportNode(section, true, ImportFormatMode.KeepSourceFormatting);
            foreach (Node insertedNode in insertedSection.Body.ChildNodes)
            {
                // Only Paragraph or Table nodes can be inserted into Cell or Shape
                if (node is Paragraph || node is Table)
                {
                    node.ParentNode.ChildNodes.Insert(index++, insertedNode);
                }
            }
        }
    }
    else
    {
        // Insertion point is tracked to Section.Body level:
        // - insert appended document on section by section basis.
        Section dstSection;
        Body body = (Body)node.GetAncestor(typeof(Body));
        if (body.LastChild != node)
        {
            DocumentBuilder builder = new DocumentBuilder(dstDoc);
            builder.MoveTo(node);
            builder.InsertBreak(BreakType.SectionBreakContinuous);
            dstSection = builder.CurrentParagraph.ParentSection;
        }
        else
        {
            dstSection = (Section)node.GetAncestor(typeof(Section));
        }
        index = dstDoc.Sections.IndexOf(dstSection);
        int index0 = index;
        foreach (Section section in doc.Sections)
        {
            insertedSection = (Section)dstDoc.ImportNode(section, true, ImportFormatMode.KeepSourceFormatting);
            dstDoc.Sections.Insert(index++, insertedSection);
        }
        dstDoc.Sections[index0].PageSetup.SectionStart = SectionStart.Continuous;
    }
}

Not sure if there has been a reply to my previous post in this thread yet, as when I click on page 2, I always get the error message:

Unknown Error
We apologize, but an unknown error has occured in the forums.
This error has been logged.

These messages unfortunately pop up frequently on the forum, sometimes they dissapear when I try to reload the page a few times, sometimes (as in this case) they insist.
I also like to note that the search function of the forum does not work properly. One always needs to perform the search again to get actual search results. And when using the advanced search (unfortunately only available after the 1st search), it seems to ignore the forum selection. This just as a side note :slight_smile:
Best Regards
Fred

Hi,
I managed to get to the 2nd page anyway by using the >> button.
Thank you very much for the code bit I used it in my project and it works wonderfully (better than the InsertHTML I had in there before as all formatting is now intact), yet please have a look at attached document.

The code inserts a continuous break before and after each document insert - which is perfectly alright - but MS Word renders the document incorrectly and treats a number of the continuous breaks as page breaks
Generated document attached.
PS: when I convert this document to PDF using Aspose.PDF, it is rendered correctly again in a PDF viewer.

Thanks Fred,
We know of these errors and will be upgrading our forums package soon. Hopefully, with a little luck, these errors will go away then. If not I will take care of them.

I suppose that the problem is due to headers/footers which are defined in the imported sections.
Try to substitute

insertedSection = (Section)dstDoc.ImportNode(section, true, ImportFormatMode.KeepSourceFormatting);
dstDoc.Sections.Insert(index++, insertedSection);

in the InsertDocument procedure with

insertedSection = (Section)dstDoc.ImportNode(section, true, ImportFormatMode.KeepSourceFormatting);
insertedSection.ClearHeadersFooters();
dstDoc.Sections.Insert(index++, insertedSection);