Creating InfoPath XML from C# - InfoPath Dev
in

InfoPath Dev

Creating InfoPath XML from C#

Last post 03-09-2011 09:38 PM by Lala Waghmode. 4 replies.
Page 1 of 1 (5 items)
Sort Posts: Previous Next
  • 09-07-2006 03:00 AM

    • victorv
    • Not Ranked
    • Joined on 02-22-2006
    • Netherlands
    • Posts 7

    Creating InfoPath XML from C#

    I have a problem writing XML from C# (.NET 1.1) that can be loaded into InfoPath and is valid according to the template's schema (XSD): XmlSerialization is mixing up fields in the output.

    Goal I want to achieve: C# (.NET 1.1) code that writes XML which is valid according to the InfoPath template schema.

    What I did:
    1. Developed an InfoPath template.
    2. Used the schema (XSD) from the template to infer a C# class using XSD.exe.
    3. Developed code to fill an instance of the C# class and serialize it to XML using XmlSerialization. (NOTE: some extra code fluff is necessary to make sure the correct processing instructions (template location) and every field are present in the XML output)
    4. Try to load the XML into InfoPath.

    Step 4 fails because the XML is not valid according to the template's schema. Some fields appear in a different order in the XML output while the schema dictates an order (sequence).

    XmlSerialization uses reflection on the C# class to create a Reader and Writer on the fly to facilitate serialization. Unfortunately, it screws up the order of fields in the output.
    And what a pain in the ass it is, because it screws up my development workflow where form 'typesafe' C# code is created by tooling from the InfoPath template.

    Does anyone have an idea to create XML from code that is valid according to the InfoPath's Template? Typesafe if possible?

    Victor
  • 09-08-2006 10:23 AM In reply to

    Re: Creating InfoPath XML from C#

    Hey Victor,

    This sounds like a very interesting scenario. How are you benefitting from generating this XML from C# using the built-in serialization methods?

    The problem you're hitting seems like a bug in the XmlSerialization class. The only advice I have in that regard is that maybe you should write your own serialization objects to make sure that it works correctly. If you do it generically enough you should be able to use them for any objects, and you could even share them with the community for all to use!

    Please let us know how this works out!
    Matt Faus / Microsoft InfoPath MVP
    Qdabra® Software / Streamline data gathering to turn process into knowledge
  • 09-13-2006 02:09 AM In reply to

    • victorv
    • Not Ranked
    • Joined on 02-22-2006
    • Netherlands
    • Posts 7

    Re: Creating InfoPath XML from C#

    Hey Matt,

    What is the benefit? I need to generate InfoPath forms from code (.NET 1.1) that can be edited later on by a human to complete.

    After much searching and trying, I came to the following conclusions:

    1. out-of-the-box XmlSerialzation generally cannot be used with InfoPath forms.

    2. The C# code class, generated by XSD.exe, is generally not easy to use if the schema of the InfoPath template uses for example DateTime fields. XSD.exe generates a valuetype DateTime which may generate a FormatException for an empty or null field when serializing.
    For serialization to work, a property based C# must be generated where empty fields can be deserialized correctly; also empty or null string fields need to produce an empty XML node instead of no XML node (I am working on both these issues).

    3. XmlSerialization in .NET 1.1 sucks, because field order is not guaranteed. The only solution I see now is to extract the on-the-fly-generated XmlSerializationWriter and change the writing order of fields by hand. I am planning to use the utility SGEN.exe http://clariusconsulting.net/blogs/kzu/archive/2004/10/21/XGenToolRelease.aspx) to extract the writer code.
    XmlSerilization in .NET 2.0 is somewhat better because support for order and nullable types can be used for value types.

  • 07-26-2007 06:01 AM In reply to

    • victorv
    • Not Ranked
    • Joined on 02-22-2006
    • Netherlands
    • Posts 7

    Re: Creating InfoPath XML from C#

    An update to my Serialization problem, because I got it to work and now have a little time to describe the solution.

    CASE: I need to read and write InfoPath forms in .NET 1.1.
    DIRECTION: Using XML Serialization.
    FACT: .NET 1.1 XML serialization does not respect the sequence specification in the XSD from the InfoPath template. In normal words: reading (de-serializing) XML from a form is fine, but writing to XML (serializing) sometimes mixes up the order of fields in the output which makes it unreadable again without exceptions.
    FACT: .NET 1.1 handles 'empty' fields that have been mapped to value types like 'int' badly (formatexception while de-serializing).

    I started using XSDObjectGen 1.4.2.1 instead of XSD.exe to generate the C# classes for serialization. These are quite different from the classes generated by XSD.exe.
    But these XSDObjectGen generated C# classes are working perfectly with .NET 1.1 XML Serialization! Both reading (deserialization) and writing (serialization) of XML form data worked like a charm.
    I can now create InfoPath forms from code! Thanks to XSDObjectGen creating data instances is a breeze in comparison to XSD.exe generated classes.

    The only snag is an XML form data contains a PREPROCESSING instruction which is be written by the XML Serialization process. I wrote a custom XmlTextWriter to solve this problem. There is some code below.

    One other important thing which is about value type fields. If you have an integer field in your InfoPath form and you don't enter a value in the form, the field in form's XML will be empty. While de-serializing, this will be a problem because the serialization engine will try to map the empty value to an integer field in the C# class -> FormatException.
    I chose to make allmost all fields in my InfoPath template a STRING. Result is that I don't have FormatExceptions, but do need to check or convert the fields in my code to apopriate types.

    This is some example C# code to write an (XSDObjectGen) class instance of an InfoPath form to a stream (for example a FileStream) to produce an XML file, which represents an InfoPath form file.

    XmlTextAndProcessingInstructionsWriter writer = new XmlTextAndProcessingInstructionsWriter(writeStream, Encoding.UTF8);

    writer.ProcessingInstructions = GetFormProcessingInstructions();
    // GetFormProcessingInstructions() = CUSTOM function to create processing instruction text, like:
    // <?xml version="1.0" encoding="UTF-8"?>
    // <?mso-infoPathSolution solutionVersion="1.0.0.67" productVersion="11.0.6357" PIVersion="1.0.0.0"
    //         href="file:///C:\SCC\Macaw.BeoordelingsProces\Doc.InfoPathTemplates\PDP.xsn" name="urn:schemas-microsoft-com:office:infopath:PDP:-myXSD-2006-02-25T22-08-56" ?>
    //        <?mso-application progid="InfoPath.Document"?>

    // Prepare namespaces for the output serialization

    new XmlTextAndProcessingInstructionsWriter(writeStream, Encoding.UTF8);

    writer.ProcessingInstructions = GetFormProcessingInstructions();
    // GetFormProcessingInstructions() = CUSTOM function to create processing instruction text, like:
    // <?xml version="1.0" encoding="UTF-8"?>
    // <?mso-infoPathSolution solutionVersion="1.0.0.67" productVersion="11.0.6357" PIVersion="1.0.0.0"
    //         href="file:///C:\SCC\Macaw.BeoordelingsProces\Doc.InfoPathTemplates\PDP.xsn" name="urn:schemas-microsoft-com:office:infopath:PDP:-myXSD-2006-02-25T22-08-56" ?>
    //        <?mso-application progid="InfoPath.Document"?>

    // Prepare namespaces for the output serialization

    // Prepare namespaces for the output serialization

    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

    // Add xsi standard to the namespace table

    new XmlSerializerNamespaces();

    // Add xsi standard to the namespace table

    // Add xsi standard to the namespace table

    ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

    // Use Reflection to retrieve the namespace from the FORM type

    // Use Reflection to retrieve the namespace from the FORM type

    Type FormType = typeof(FORM);  // FORM is an XSDObjectGen generated class

    XmlRootAttribute[] xmlRootAttrs = (XmlRootAttribute[])FormType.GetCustomAttributes(typeof(System.Xml.Serialization.XmlRootAttribute), false);

    if (xmlRootAttrs.Length > 0)

    {

       ns.Add("my", xmlRootAttrs[0].Namespace);

    }

    typeof(FORM);  // FORM is an XSDObjectGen generated class

    XmlRootAttribute[] xmlRootAttrs = (XmlRootAttribute[])FormType.GetCustomAttributes(typeof(System.Xml.Serialization.XmlRootAttribute), false);

    if (xmlRootAttrs.Length > 0)

    {

       ns.Add("my", xmlRootAttrs[0].Namespace);

    }

    typeof(System.Xml.Serialization.XmlRootAttribute), false);

    if (xmlRootAttrs.Length > 0)

    {

       ns.Add("my", xmlRootAttrs[0].Namespace);

    }

    if (xmlRootAttrs.Length > 0)

    {

       ns.Add("my", xmlRootAttrs[0].Namespace);

    }

    XmlSerializer ser = new XmlSerializer(typeof(FORM));

    ser.Serialize(writer, formdata, ns);   // formdata is an instance of the XSDObjectGen generated class

    new XmlSerializer(typeof(FORM));

    ser.Serialize(writer, formdata, ns);   // formdata is an instance of the XSDObjectGen generated class

     

    /// <summary>

    /// The XmlTextAndProcessingInstructionsWriter is derived from XmlTextWriter and

    <summary>

    /// The XmlTextAndProcessingInstructionsWriter is derived from XmlTextWriter and

    The XmlTextAndProcessingInstructionsWriter is derived from XmlTextWriter and

    /// writes out the attached xml processing instructions when writing the xml.

    writes out the attached xml processing instructions when writing the xml.

    /// Attach the processing instructions collection to the writer before writing

    Attach the processing instructions collection to the writer before writing

    /// the xml document. The writer will output the processing instructions at the correct

    the xml document. The writer will output the processing instructions at the correct

    /// location in the xml file.

    location in the xml file.

    /// </summary>

    </summary>

    public class XmlTextAndProcessingInstructionsWriter : XmlTextWriter

    {

    class XmlTextAndProcessingInstructionsWriter : XmlTextWriter

    {

    private NameValueCollection _processingInstructions = new NameValueCollection();

    NameValueCollection _processingInstructions = new NameValueCollection();

    public XmlTextAndProcessingInstructionsWriter(TextWriter w) : base(w)

    {

    Init();

    }

    XmlTextAndProcessingInstructionsWriter(TextWriter w) : base(w)

    {

    Init();

    }

    public XmlTextAndProcessingInstructionsWriter(string filename, Encoding encoding) : base(filename, encoding)

    {

    Init();

    }

    XmlTextAndProcessingInstructionsWriter(string filename, Encoding encoding) : base(filename, encoding)

    {

    Init();

    }

    public XmlTextAndProcessingInstructionsWriter(Stream w, Encoding encoding) : base(w, encoding)

    {

    Init();

    }

    XmlTextAndProcessingInstructionsWriter(Stream w, Encoding encoding) : base(w, encoding)

    {

    Init();

    }

    private void Init()

    {

    this.Formatting = Formatting.Indented;

    }

    void Init()

    {

    this.Formatting = Formatting.Indented;

    }

    this.Formatting = Formatting.Indented;

    }

    public NameValueCollection ProcessingInstructions

    {

    set { this._processingInstructions = value; }

    }

    NameValueCollection ProcessingInstructions

    {

    set { this._processingInstructions = value; }

    }

    set { this._processingInstructions = value; }

    }

    public override void WriteStartDocument()

    {

    base.WriteStartDocument();

    WriteProcessingInstructions();

    }

    override void WriteStartDocument()

    {

    base.WriteStartDocument();

    WriteProcessingInstructions();

    }

    base.WriteStartDocument();

    WriteProcessingInstructions();

    }

    public override void WriteStartDocument(bool standalone)

    {

    base.WriteStartDocument(standalone);

    WriteProcessingInstructions();

    }

    override void WriteStartDocument(bool standalone)

    {

    base.WriteStartDocument(standalone);

    WriteProcessingInstructions();

    }

    base.WriteStartDocument(standalone);

    WriteProcessingInstructions();

    }

    private void WriteProcessingInstructions()

    {

    if (this._processingInstructions != null)

    {

    foreach(string key in this._processingInstructions.AllKeys)

    {

    WriteProcessingInstruction(key, this._processingInstructions[key]);

    }

    }

    }

    void WriteProcessingInstructions()

    {

    if (this._processingInstructions != null)

    {

    foreach(string key in this._processingInstructions.AllKeys)

    {

    WriteProcessingInstruction(key, this._processingInstructions[key]);

    }

    }

    }

    if (this._processingInstructions != null)

    {

    foreach(string key in this._processingInstructions.AllKeys)

    {

    WriteProcessingInstruction(key, this._processingInstructions[key]);

    }

    }

    }

    foreach(string key in this._processingInstructions.AllKeys)

    {

    WriteProcessingInstruction(key, this._processingInstructions[key]);

    }

    }

    }

    this._processingInstructions[key]);

    }

    }

    }

     

  • 03-09-2011 09:38 PM In reply to

    Re: Creating InfoPath XML from C#

     Hello Matt.

    I read your blogs and came to know,you have a answer for my query.

    please give me a code and exact references for my assignment.

    I have to convert any infopath template into XML for platform interoperability.

    I am waiting...

    Best Regards,

    Lala

     

     

Page 1 of 1 (5 items)
Copyright © 2003-2019 Qdabra Software. All rights reserved.
View our Terms of Use.