The mainstream practice in .NET is to use XML Serialization.
In your case, I would do this:
- run the xsd.exe too on .XSD to generate source code for classes (xsd /c)
- build your app that utilizes those generated classes. Keep in mind you can extend those classes via the "partial classes" technique
- in code, instantiate an XmlSerializer, and Serialize the class instances.
Example:
Given this schema:
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Foo" nillable="true" type="Foo" />
<xs:complexType name="Foo">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Bar" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="Baz" type="UntypedArray" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="UntypedArray">
<xs:choice minOccurs="1" maxOccurs="unbounded">
<xs:element name="Type1" type="Type1" minOccurs="1" maxOccurs="1"/>
<xs:any namespace="##other" processContents="lax" minOccurs="1" maxOccurs="1"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="Type1" mixed="true">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Child" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
xsd.exe generates this source code:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)]
public partial class Foo {
private string barField;
private object[] bazField;
/// <remarks/>
public string Bar {
get {
return this.barField;
}
set {
this.barField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlArrayItemAttribute("", typeof(System.Xml.XmlElement), IsNullable=false)]
[System.Xml.Serialization.XmlArrayItemAttribute(typeof(Type1), IsNullable=false)]
public object[] Baz {
get {
return this.bazField;
}
set {
this.bazField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public partial class Type1 {
private string childField;
private string[] textField;
/// <remarks/>
public string Child {
get {
return this.childField;
}
set {
this.childField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public string[] Text {
get {
return this.textField;
}
set {
this.textField = value;
}
}
}
In your app you can instantiate a Foo and then serialize, like this:
Foo foo = new Foo();
// ...populate foo here...
var builder = new System.Text.StringBuilder();
XmlSerializer s = new XmlSerializer(typeof(Foo));
using ( var writer = System.Xml.XmlWriter.Create(builder))
{
s.Serialize(writer, foo, ns);
}
string rawXml = builder.ToString();
This example serializes into a string. Of course you can serialize to other XmlWriters, you can write out to a file, to any arbitrary stream, and so on.
Normally I tweak the serialization to omit the XML declaration, omit the default xml namespaces, and so on. Like this:
Foo foo = new Foo();
// ...populate foo here...
var builder = new System.Text.StringBuilder();
var settings = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };
var ns = new XmlSerializerNamespaces();
ns.Add("","");
XmlSerializer s = new XmlSerializer(typeof(Foo));
using ( var writer = System.Xml.XmlWriter.Create(builder, settings))
{
s.Serialize(writer, foo, ns);
}
string rawXml = builder.ToString();
You can also do the reverse - map from an XML document to an in-memory object graph - using the XmlSerializer. Use the Deserialize method.