Pergunta

I have infopath 2010 form. designed as Student information. I want to generate the report as word document using OpenXMl with specified report template. To I designed the form in such away that,

  • All fields are place on infopath form as text for now.

  • and added the button control.

  • On Button click i am fetching the values of fields by using XPathNavigator objects.
  • Now i have set of string variables with values.
  • I have prepared the .dotx file with content controls. ( Do i need to give id to each control )

But unable to understand how can i map my variables values to the word template content controls programatically using c#. [Herewith][1] the great example of the OpenXMl with web. but it is using custom Xml Part , which uses for dumping data from xml file to word template.

What i have to do to map my string variables with template content controls? any reference link for this ?

Foi útil?

Solução

I've had to acheive something very similar, and i ended up using custom "PlaceHolder" fields instead of the Word fields (they do have various limitations like - header, footer and body all using different objects).

In my word template, i marked a PlaceHolder like this - ##MyPlaceHolderName!#. Then i parsed the text of the word template to find all PlaceHolders using RegEx and replaced them with the actual values of the InfoPath Form.

The only downside with this solution is, that your PlaceHolders and your InfoPath fields will need to have the same name, otherwise you won't be able to do any matching.

Consider this method:

private void FillDocument(Stream documentStream, string xmlFields)
{
    var doc = new XmlDocument();
    doc.LoadXml(xmlFields);

    var props = doc.SelectSingleNode("properties");
    if (props == null) throw new Exception("No properties found.");

    //transform the xml properties to dictionary for easier replacement
    var fields = props.ChildNodes.Cast<XmlNode>().ToDictionary
        (node => string.Format("##{0}!#", node.Name), node => node.InnerText);


    using (var document = WordprocessingDocument.Open(documentStream, true))
    {
        var main = document.MainDocumentPart;

        //replace the fields in the main document
        main.Document.InnerXml = ReplaceFields(main.Document.InnerXml, fields);

        //replace the fields in the headers
        foreach (var headerPart in main.HeaderParts)
            headerPart.Header.InnerXml = ReplaceFields(headerPart.Header.InnerXml, fields);

        //replace the fields in the footers
        foreach (var footerPart in main.FooterParts)
            footerPart.Footer.InnerXml = ReplaceFields(footerPart.Footer.InnerXml, fields);

        main.Document.Save();
    }
}

private string ReplaceFields(string xmlPart, Dictionary<string, string> fields)
{
    //searches the xml for the declared fields
    var fieldRegex = new Regex("##[^#]*!#");
    var matches = fieldRegex.Matches(xmlPart);

    foreach (Match match in matches)
    {
        //the fields are within tags (InnerText) so remove all other xml stuff
        var innerRegex = new Regex("<[^>]*>");
        string fieldName = innerRegex.Replace(match.Groups[0].Value, "");

        //replace the actual value of the field
        if(fields.ContainsKey(fieldName))
            xmlPart = xmlPart.Replace(match.Groups[0].Value, fields[fieldName]);
    }

    return xmlPart;
}

You'd use it as followed:

//open the file from as stream (in this example, the file is opened from SP
using (var stream = templateFile.OpenBinaryStream())
{
    //iterate the properties you need and add them in this format 
    var xmlProperties = "<properties><MyPlaceHolderName>MyPlaceHolderValue</MyPlaceHolderName></properties>";

    //fill out the fields
    FillDocument(stream, xmlProperties);
}

I know the Xml-Replacing and xmlProperties are relatively crazy, but i had to implement it like this due my requirements (method is called by a WebService from InfoPath). Let me know if you need further assistence.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top