Reputation: 161
I have been cursed with a project requiring the creation of an application in InfoPath that employs gigantic forms. In order to access the data from the InfoPath XML I've chosen to use the XSD utility to create a serialized c# class based on the InfoPath generated XML schema.
Since the InfoPath form contains several tables, the tables are implemented in the serialized class as arrays of the row type. When the XML is read in (deserialized) array elements are obviously being allocated and populated.
What I can't figure out is how to add additional array elements. For example, if the XML has two entries in the table, the array will have two elements allocated. But I'd like to be able to add additional elements to the array.
I tried to use the Array.Resize method without much luck.
This sound familiar to anyone?
-Tom
Upvotes: 3
Views: 2474
Reputation: 27339
I would make use of extension methods (or partial classes) to allow for easy addition of items to the arrays in the classes created by XSD.exe. Since XSD.exe generates arrays and not lists, adding elements to the arrays is a bit cumbersome. If you use extension methods, you can make the classes easier to work with.
The sample code below is based on a set of classes I created using the following xml:
<?xml version="1.0" encoding="utf-8" ?>
<Doc>
<Item Text="A" />
<Item Text="B" />
<Item Text="C" />
<Item Text="D" />
</Doc>
The following program deserializes the above XML into a Doc
object, and takes advantage of the AddDocItem
extension method to add items to the Doc.Items
array. AddDocItem
makes use of Array.Resize
to add the elements.
using System;
using System.IO;
using System.Xml.Serialization;
namespace TestConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var xmlSerialzer = new XmlSerializer(typeof(Doc));
var doc = xmlSerialzer.Deserialize(
new StreamReader(@"..\..\XmlFile1.xml")) as Doc;
if(doc == null) return;
doc.PrintDocItems();
Console.WriteLine();
//Add a couple new items
doc.AddDocItem(new DocItem { Text = "E" });
doc.AddDocItem(new DocItem { Text = "F" });
doc.PrintDocItems();
}
}
public static class DocExtensions
{
public static void AddDocItem(this Doc doc, DocItem item)
{
var items = doc.Items;
Array.Resize(ref items, items.Length + 1);
items[items.Length - 1] = item;
doc.Items = items;
}
public static void PrintDocItems(this Doc doc)
{
foreach (var item in doc.Items)
Console.WriteLine(item.Text);
}
}
}
If you are not a fan of extension methods, you can take advantage of the fact that the classes generated by XSD.exe are partial classes, and extend the classes that way. For example:
public partial class Doc
{
public void AddDocItem(DocItem item)
{
var items = Items;
Array.Resize(ref items, items.Length + 1);
items[items.Length - 1] = item;
Items = items;
}
public void PrintDocItems()
{
foreach (var item in Items)
Console.WriteLine(item.Text);
}
}
Either way should work fine.
The code generated by XSD.exe is shown below for reference:
namespace TestConsoleApplication1
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class Doc {
private DocItem[] itemsField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("Item", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public DocItem[] Items {
get {
return this.itemsField;
}
set {
this.itemsField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class DocItem {
private string textField;
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string Text {
get {
return this.textField;
}
set {
this.textField = value;
}
}
}
}
Hope that helps.
Upvotes: 4