Processing of recursive elements using SampleGenericDocumentGeneratorUsingXml

Apr 2, 2012 at 2:37 PM
Edited Apr 2, 2012 at 5:01 PM

Dear atul,

first I would like to thank you for sharing this usefull code with the community. This was exactlly what I was looking for and started to write a version by myself, luckily you released your version just on right time.

The question that makes me write is the processing of recursive fields, more specifically, I have a situation where tables are nested in tables. I don't know if its is a restriction of Control Element but the point is that by now its not working or I and doing something wrong, in both cases I appreciate a little help.

The code I expect to work is the following:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using WordDocumentGenerator.Library;
using System.IO;

namespace WordDocumentGenerator.Client
{
    class RecursiveExample
    {
        static void Main(string[] args)
        {
            // There are three sample document templates i.e. Test_Template - 1.docx, Test_Template - 1.docx and Test_Template - Final.docx
            // The only difference between Test_Template - 1.docx and Test_Template - 2.docx is that Test_Template - 2.docx contains table. This table has it's own
            // content control tags. Rest is same. Hence I'll be reusing the code inside generators wherever possible.
            // Test_Template - Final.docx contains only cover page and is used to create a final report by appending documents.

            Console.WriteLine("Started execution of samples ...");
            Console.WriteLine("Generated documents will be saved to - " + Path.GetFullPath(@"Sample Templates\"));
            Console.WriteLine();


            // Test document generation from template("planning1.docx")
            // The template contains table inside table, a multi-level recursion.
            string dataAsXml = "<field>" +
                                    "<listFields>" +
                                        "<field planningName=\"2012 planning\" id=\"\" contentControlTagREFS=\"terminal1\"/>" +
                                        "<field planningDescription=\"Description of 2012 planning\" id=\"\" contentControlTagREFS=\"terminal2\"/>" +
                                        "<field id=\"\" contentControlTagREFS=\"container1\">" +
                                            "<listFields>" +

                                                //THIAGO: to perform multiple columns in recursive fields I had to use 'listFields' instad of 'fields'
                                                // in RecursivePlaceholderFound method of SampleGenericDocumentGeneratorUsingXml.
                                                //XPathNodeIterator nodeIterator = navigator.SelectChildren("listFields", (openXmlElementDataContext.DataContext as XmlNode).NamespaceURI);

                                                // THIS IS THE FIRST LEVEL OF RECURSION
                                                "<field id=\"\" contentControlTagREFS=\"recursive1\">" +
                                                    "<listFields>" +
                                                        "<field processName=\"Hiring\" id=\"\" contentControlTagREFS=\"terminal3\"/>" +
                                                        // THIS IS THE SECOND LEVEL OF RECURSION
                                                        "<field id=\"\" contentControlTagREFS=\"recursive2\">" +
                                                            "<listFields>" +
                                                                "<field processUnit=\"HR\" id=\"\" contentControlTagREFS=\"terminal4\" />" +
                                                                "<field processUnit=\"Finance\" id=\"\" contentControlTagREFS=\"terminal4\" />" +
                                                            "</listFields>" +
                                                        "</field>" +
                                                    "</listFields>" +
                                                    "<listFields>" +
                                                        "<field processName=\"Publicity\" id=\"\" contentControlTagREFS=\"terminal3\"/>" +
                                                        // THIS IS THE SECOND LEVEL OF RECURSION
                                                        "<field id=\"\" contentControlTagREFS=\"recursive2\">" +
                                                            "<listFields>" +
                                                                "<field processUnit=\"PR\" id=\"\" contentControlTagREFS=\"terminal4\" />" +
                                                                "<field processUnit=\"Marketing\" id=\"\" contentControlTagREFS=\"terminal4\" />" +
                                                                "<field processUnit=\"Owners\" id=\"\" contentControlTagREFS=\"terminal4\" />" +
                                                            "</listFields>" +
                                                        "</field>" +
                                                    "</listFields>" +
                                                "</field>" +
                                            "</listFields>" +
                                        "</field>" +
                                    "</listFields>" +
                                    "<contentControls>" +
                                        "<contentControl type=\"2\" tag=\"terminal1\" refControlValue=\"planningName\" refTagValue=\"id\"/>" +
                                        "<contentControl type=\"2\" tag=\"terminal2\" refControlValue=\"planningDescription\" refTagValue=\"id\"/>" +
                                        "<contentControl type=\"4\" tag=\"container1\" refTagValue=\"id\"/>" +
                                        "<contentControl type=\"1\" tag=\"recursive1\" refTagValue=\"id\"/>" +
                                        "<contentControl type=\"1\" tag=\"recursive2\" refTagValue=\"id\"/>" +
                                        "<contentControl type=\"2\" tag=\"terminal3\" refControlValue=\"processName\" refTagValue=\"id\"/>" +
                                        "<contentControl type=\"2\" tag=\"terminal4\" refControlValue=\"processUnit\" refTagValue=\"id\"/>" +
                                    "</contentControls>" +
                                "</field>";

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(dataAsXml);
            string template = "planning1.docx";
            DocumentGenerationInfo generationInfo = GetDocumentGenerationInfo("SampleGenericDocumentGeneratorUsingXml", "1.0", xmlDoc.DocumentElement,
                                        template, false);
            SampleGenericDocumentGeneratorUsingXml sampleGenericDocumentGeneratorUsingXml = new SampleGenericDocumentGeneratorUsingXml(generationInfo);
            byte[] result = sampleGenericDocumentGeneratorUsingXml.GenerateDocument();
            WriteOutputToFile("planningOut1.docx", template, result);
        }

        /// <summary>
        /// Gets the document generation info.
        /// </summary>
        /// <param name="docType">Type of the doc.</param>
        /// <param name="docVersion">The doc version.</param>
        /// <param name="dataContext">The data context.</param>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="useDataBoundControls">if set to <c>true</c> [use data bound controls].</param>
        /// <returns></returns>
        private static DocumentGenerationInfo GetDocumentGenerationInfo(string docType, string docVersion, object dataContext, string fileName, bool useDataBoundControls)
        {
            DocumentGenerationInfo generationInfo = new DocumentGenerationInfo();
            generationInfo.Metadata = new DocumentMetadata() { DocumentType = docType, DocumentVersion = docVersion };
            generationInfo.DataContext = dataContext;
            generationInfo.TemplateData = File.ReadAllBytes(Path.Combine("Sample Templates", fileName));
            generationInfo.IsDataBoundControls = useDataBoundControls;
            return generationInfo;
        }

        /// <summary>
        /// Writes the output to file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="templateName">Name of the template.</param>
        /// <param name="fileContents">The file contents.</param>
        private static void WriteOutputToFile(string fileName, string templateName, byte[] fileContents)
        {
            ConsoleColor consoleColor = Console.ForegroundColor;

            fileName = Path.Combine(Path.GetFullPath("Sample Templates"), fileName);
            if (fileContents != null)
            {
                File.WriteAllBytes(fileName, fileContents);
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(string.Format("Generation succeeded for template({0}) --> {1}", templateName, fileName));
                Console.WriteLine();
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(string.Format("Generation failed for template({0}) --> {1}", templateName, fileName));
            }

            Console.ForegroundColor = consoleColor;

            Console.WriteLine("Press any key.");
            Console.ReadLine();
        }

    }
}
The expected result is something like:
       Name: 2012 planning
Description: Description of 2012 planning
+---------------------------------------------+
| Name                 | Units                |
-----------------------------------------------
| Hiring               | RH                   |
|                      | Finance              |
-----------------------------------------------
| Marketing            | PR                   |
|                      | Marketing            |
|                      | Owners               |
-----------------------------------------------
But the current result is:
+---------------------------------------------+
| Name                 | Units                |
-----------------------------------------------
| Hiring               | RH                   |
-----------------------------------------------
| Marketing            | PR                   |
-----------------------------------------------

Ps: If you prefer I can send to you the template itself, and the imagens or expected and received results. Its just ask in thiagosaint AT gmail DOT com.

Another point is that to perfom multi-column replacement I had to change SampleGenericDocumentGeneratorUsingXml, as specified in the example comments.

Considering that multi-level templates are common, and required for the software I am working on,  I would like to know if I have made something wrong, or is there something missing in your API.

Thanks in advance,

Thiago

Coordinator
Apr 2, 2012 at 9:30 PM

I've replied you @ thiagosaint AT gmail DOT com. Do share the template. Thanks.

 

Regards,

Atul

Apr 2, 2012 at 9:46 PM

Hi Atul,

thanks for your interest. The template and the posted code are attached.

I hope it can help to improve your tool, or at least to figure out what am I doing wrong.

Regards,

Thiago

2012/4/2 atul_nith <notifications@codeplex.com>

From: atul_nith

I've replied you @ thiagosaint AT gmail DOT com. Do share the template. Thanks.

Regards,

Atul

Read the full discussion online.

To add a post to this discussion, reply to this email (WordDocGenerator@discussions.codeplex.com)

To start a new discussion for this project, email WordDocGenerator@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com




--
---------------------+
Thiago Santos
Apr 2, 2012 at 9:47 PM

I´ve just answered with the template file. Thanks.

Regards,

Thiago.

Coordinator
Apr 2, 2012 at 10:50 PM

I didn't find the template file. If possible share the download location.

 

Regards,

Atul

Apr 2, 2012 at 11:04 PM

Hi, I sent to your Gmail.

 

Regards,

 

Thiago.

Coordinator
Apr 2, 2012 at 11:07 PM

Your mail isn't there. Can you verify again.

 

Regards,

Atul

Apr 2, 2012 at 11:09 PM
Edited Apr 2, 2012 at 11:17 PM

BTW,

why not using fields as tag values instead of tag attributes? For example, instead of:

 

<field planningName="2012 planning" id="" contentControlTagREFS="terminal1"/>

 

we could have:

<field name="planningName" id="" contentControlTagREFS="terminal1">2012 planning</field>

Or

<field name="planningName" id="" contentControlTagREFS="terminal1">
    <![CDATA[2012 planning > 2012 planning]]>
</field>

It would allow us to have bigger texts and avoids XML restrictions on attributes.

Coordinator
Apr 3, 2012 at 5:55 AM

I ran the code you shared against the template mailed and was getting the expected results. Are you using the latest source code. I was able to see HR & Finance under Hiring and PR, Marketing & Owners under Publicity.

The suggestion to avoid attributes sounds great. You can easily do that and just need to modify a couple of methods i.e. Parse and GetPlaceHolderTagToTypeCollection of SampleGenericDocumentGeneratorUsingXml class.

 



Apr 3, 2012 at 5:25 PM

Atul,

I downloaded the source code last saturday. Anyway, its great to know it works! :) I'll both download and try, again asap.

About the attributes, suppose I change the SampleGenericDocumentGeneratorUsingXml implementation to avoid use of attributes, would you mind to update your distribution (of course after code exam) with this new version? Or do you prefer that I create another file, let say, SampleGenericDocumentGeneratorUsingXmlValues? I think this last option is better to the fellows which already started using SampleGenericDocumentGeneratorUsingXml.

Thanks!

Coordinator
Apr 4, 2012 at 5:24 AM

Yeah the second option sounds good. This will ensure that choice is there between choosing attributes or fields. Do mail the complete source code in case you still face the issue. Thanks.

 

Regards,

Atul

Jul 13, 2012 at 9:37 PM

Thiago,

the xml should be:

<field>
  <listFields>
    <field planningName="2012 planning" id="" contentControlTagREFS="terminal1" />
    <field planningDescription="Description of 2012 planning" id="" contentControlTagREFS="terminal2" />
    <field id="" contentControlTagREFS="container1">
      <listFields>
        <field id="" contentControlTagREFS="recursive1">
          <listFields>
            <field processName="Hiring" id="" contentControlTagREFS="terminal3">
              <listFields>
                <field id="" contentControlTagREFS="recursive2">
                  <listFields>
                    <field processUnit="HR" id="" contentControlTagREFS="terminal4" />
                    <field processUnit="Finance" id="" contentControlTagREFS="terminal4" />
                  </listFields>
                </field>
              </listFields>
            </field>
            <field processName="Publicity" id="" contentControlTagREFS="terminal3">
              <listFields>
                <field id="" contentControlTagREFS="recursive2">
                  <listFields>
                    <field processUnit="PR" id="" contentControlTagREFS="terminal4" />
                    <field processUnit="Marketing" id="" contentControlTagREFS="terminal4" />
                    <field processUnit="Owners" id="" contentControlTagREFS="terminal4" />
                  </listFields>
                </field>
              </listFields>
            </field>
          </listFields>
        </field>
      </listFields>
    </field>
  </listFields>
  <contentControls>
    <contentControl type="2" tag="terminal1" refControlValue="planningName" refTagValue="id" />
    <contentControl type="2" tag="terminal2" refControlValue="planningDescription" refTagValue="id" />
    <contentControl type="4" tag="container1" refTagValue="id" />
    <contentControl type="1" tag="recursive1" refTagValue="id" />
    <contentControl type="1" tag="recursive2" refTagValue="id" />
    <contentControl type="2" tag="terminal3" refControlValue="processName" refTagValue="id" />
    <contentControl type="2" tag="terminal4" refControlValue="processUnit" refTagValue="id" />
  </contentControls>
</field>