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 serializationXmlSerializerNamespaces 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 tablens.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 typeType FormType = typeof(FORM); // FORM is an XSDObjectGen generated classXmlRootAttribute[] 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 classXmlRootAttribute[] 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]);}
}
}