I am fairly new to XML in .net. As part of my task i need to create the class which can be serialized to XML. I have an sample XML file with all the tags(the class should produce XML similar to the sample XML file ). what would be best approach to create the class from XML file?
Thank you in advance!!
You can use XSD.exe to create a .cs file from .xml.
http://msdn.microsoft.com/en-us/library/x6c1kb0s%28VS.71%29.aspx
At the command line:
xsd myFile.xml
xsd myFile.xsd
The first line will generate a schema definition file (xsd), the second file should generate a .cs file. I'm not sure if the syntax is exact, but it should get you started.
Working backwards might help -- create your class first, then serialize and see what you get.
For the simplest classes it's actually quite easy. You can use XmlSerializer to serialize, like:
namespace ConsoleApplication1
{
public class MyClass
{
public string SomeProperty
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
TextWriter writer = new StreamWriter(#"c:\temp\class.xml");
MyClass firstInstance = new MyClass();
firstInstance.SomeProperty = "foo"; // etc
serializer.Serialize(writer, firstInstance);
writer.Close();
FileStream reader = new FileStream(#"c:\temp\class.xml", FileMode.Open);
MyClass secondInstance = (MyClass)serializer.Deserialize(reader);
reader.Close();
}
}
}
This will write a serialized representation of your class in XML to "c:\temp\class.xml". You could take a look and see what you get. In reverse, you can use serializer.Deserialize to instantiate the class from "c:\temp\class.xml".
You can modify the behaviour of he serialization, and deal with unexpected nodes, etc -- take a look at the XmlSerializer MSDN page for example.
here's a good example how to serialize/deserialize an object. http://sharpertutorials.com/serialization/
Related
I've searched but couldn't find anything similar as this is probably very basic. I'm basically trying to read a list of movies from an xml file and then to pass it back into a Model for various types of consumption. But I get a "System.NullReferenceException: Object reference not set to an instance of an object." My (sudo) c# code looks something like this
var xmlDoc = new XmlDocument();
xmlDoc.Load("c:\\movies.xml");
var movieModel = new MovieSummary();
var MovieXML = xmlDoc.GetElementsByTagName("movie");
int i;
for (i = 0; i < MovieXML.Count; i++)
{
movieModel.Movies[i].name = MovieXML[i]["name"].toString();
}
my Model looks like this
namespace movies.Models
{
public class MovieSummary
{
public List<Movie> Movies { get; set; }
}
public class Movie
{
public string movie { get; set; }
}
}
xml file looks like
<movies xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<movie>
<name>The Dark Knight</name>
</movie>
<movie>
<name>Iron Man</name>
</movie>
</movies>
I think you are better off with using XmlSerializer if the structure of your xml file is resembled in your classes by inheritance.
Write a function which Deserialize your xml to your classes.
public static MovieSummary Deserialize()
{
XmlSerializer serializer = new XmlSerializer(typeof(MovieSummary));
TextReader textReader;
textReader = new StreamReader(pathtoyourxmlfile);
MovieSummary summary = (MovieSummary)serializer.Deserialize(textReader);
textReader.Close();
return summary;
}
Hope that helps
If you are ONLY going to ever be loading a list of movies from an xml file, and that't it, you should check out the following link on MSDN:
http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.getelementsbytagname%28v=vs.71%29.aspx
This would be a solution for that approach:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var xmlDoc = new XmlDocument();
xmlDoc.Load("c:\\movies.xml");
var movieModel = new MovieSummary();
var MovieXML = xmlDoc.GetElementsByTagName("movie");
movieModel.Movies = new List<Movie>();
foreach (XmlElement element in MovieXML)
{
movieModel.Movies.Add(new Movie(){movie = element.InnerText});
}
//for (i = 0; i < MovieXML.Count; i++)
//{
// movieModel.Movies[i].name = MovieXML[i]["name"].toString();
//}
}
}
}
If you are going to plan on loading anything more than just movies from the xml file or you think you'll ever need more flexibility in loading multiple nodes from multiple xml files, I'd advise using the xmlserialization ability of .NET via the xsd.exe tool. Do your xml files adhere to a common xsd schema. If they dont, dont worry, you can create a common schema for your xml files using xsd.exe (its part of visual studio). Once you have generated the xsd file from your sample xml file, you can use that xsd file to generate classes using that same xsd.exe tool.
Once that is done, you can add the generated class or classes to your model as members, wrap them as you see fit, and bulk load the data from the xml file into the member classes with a few lines of code. And that will work for any xml file so long as it adheres to said xsd file. You an also load and unload the data to and from xml file to and from classes using serializer classes.
There are many ways to do what you are talking about, and I've tried many ways. However, this by far the best way to do things because it allows you to load as many different xml files as you want without having to rewrite the methods that load the xml (Again, as long as what you're loading adheres to the xsd file).
http://msdn.microsoft.com/en-us/library/x6c1kb0s%28v=vs.71%29.aspx
There are lots of examples on the web of transforming an XML file to a different format using an XSLT file, like the following:
XslTransform myXslTransform = new XslTransform();
XsltSettings myXsltSettings = new XsltSettings();
myXsltSettings.EnableDocumentFunction = true;
myXslTransform.Load("transform.xsl");
myXslTransform.Transform("input.xml", "output.xml");
However this is only a partial answer, I would like to be able to get the XML input data from a web form and use that as the input xml data instead of an '.xml' file, but have not found any concrete examples. Using Visual Studio I see Load methods that accept XmlReader objects as parameters but I do not know how to create one of those using the data from a form and TextBox control. It would be very helpful if someone could provide an example of transforming XML using form data instead of an input file.
Create a class and populate an instance of this class during postback from your form data and serialize it ( convert it to xml)
Here is console example for you
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace Stackoverflow
{
public class Program
{
static void Main(string[] args)
{
var p = new Person
{
FirstName = "Daniel", /// in your case you get it from the form
LastName = "Endeg"
};
var x = new XmlSerializer(p.GetType());
x.Serialize(Console.Out, p);
Console.WriteLine();
Console.ReadLine();
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
Please note that XslTransform is obsolete since .NET 2.0, you should use XslCompiledTransform instead. And if you want to use XslSettings then make sure you pass them in to the XslCompiledTransform's Load method (e.g. http://msdn.microsoft.com/en-us/library/ms163425.aspx), simply creating it does not make sense.
As for parsing XML you have in a string variable or property (like the Text property of a TextBox) you have lots of options, you can use an XmlReader over a StringReader e.g.
XslCompiledTransform proc = new XslCompiledTransform();
proc.Load("sheet.xsl");
using (StringReader sr = new StringReader(TextBox1.Text))
{
using (XmlReader xr = XmlReader.Create(sr))
{
proc.Transform(xr, null, Response.Output);
}
}
Or you can create an XPathDocument or XmlDocument or XDocument from the string and use an overload of the Transform method that takes an IXPathNavigable as the first argument.
Ok, with some help from Visual Studio auto-complete which lists the parameters for constructors and methods, I was able to complete a working answer to the problem above, using strings for input and output in an Xslt transform operation. Yay. The example answer below assumes you have three strings containing the Xslt text data and the input Xml text data and output Xml data:
string XsltText;
string InputXML;
string OutputXml;
// define the xslt from a string
TextReader myXsltText = new StringReader(XsltText);
XmlReader myXslt = new XmlTextReader(myXsltText);
// define the input xml from a string
TextReader myXmlText = new StringReader(InputXML);
XmlReader myInputXml = new XmlTextReader(myXmlText);
// define the output XmlWriter for the results of the transform
TextWriter myOutputXmlTextWriter = new StringWriter();
XmlWriter myOutputXml = new XmlTextWriter(myOutputXmlTextWriter);
XslCompiledTransform myXslTransform = new XslCompiledTransform();
XsltSettings myXsltSettings = new XsltSettings();
myXsltSettings.EnableDocumentFunction = true;
myXslTransform.Load(myXslt);
myXslTransform.Transform(myInputXml, myOutputXml);
// the result from the transform comes from the TextWriter object
OutputXml = myOutputXmlTextWriter.ToString();
// clean up writers
myOutputXml.Flush();
myOutputXmlTextWriter.Close();
myOutputXml.Close();
To get this code working with a web form, all you have to do is get the strings from the value (Text) of the form elements (controls), for the input XMl and Xslt you could use TextBox controls, and to display the results you could use a label, all very useful, if anyone has a better answer please feel free to let me know.
This is killing me. I've read these:
http://msdn.microsoft.com/en-us/library/athddy89(v=VS.80).aspx
http://msdn.microsoft.com/en-us/library/2baksw0z(v=VS.80).aspx
But I don't see how to apply them to what I'm trying to do. I want to customize the way the following list serializes...
[Serializable]
public class FinalConcentrations : List<string> { }
so that when I pass it as the "objectToSerialze" to this...
public void serializeObject(object objectToSerialize, Stream outputStream)
{
// removes the default added namespaces
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serial = new XmlSerializer(objectToSerialize.GetType());
MemoryStream ms = new MemoryStream();
serial.Serialize(ms, objectToSerialize, ns);
StreamReader reader = new StreamReader(ms);
ms.Position = 0;
ms.WriteTo(outputStream);
}
...it writes this to the output stream:
<FinalConcentrations>
<FinalConcentration>string value 1</FinalConcentration>
<FinalConcentration>string value 2</FinalConcentration>
<FinalConcentration>string value 3</FinalConcentration>
</FinalConcentration>
...instead of this
<FinalConcentrations>
<string>string value 1</string>
<string>string value 2</string>
<string>string value 3</string>
</FinalConcentration>
My serializeObject method is used to serialize a wide variety of objects, so I'm looking for a way to do this in my FinalConcentrations definition rather than within that method.
Please, help.
The easiest way to fix that is to pass in a wrapper object instead of the list itself, i.e.
public class FinalConcentrations {
private readonly List<string> items = new List<string>();
[XmlElement("FinalConcentration")]
public List<string> Items {get {return items;}}
}
that do?
Well, when I ran your example I actually got
<?xml version="1.0"?>
<ArrayOfString>
<string>Red</string>
<string>Green</string>
<string>Blue</string>
</ArrayOfString>
but by changing
[Serializable, XmlRoot( ElementName= "FinalConcentrations")]
public class FinalConcentrations : List<string> { }
I got
<?xml version="1.0"?>
<FinalConcentrations>
<string>Red</string>
<string>Green</string>
<string>Blue</string>
</FinalConcentrations>
QED?
There are a whole bunch of XML decorator attributes that can change the serialisation, eg. XmlElement. Worth having a look at.
Best of luck.
I am receiving XML strings over a socket, and would like to convert these to C# objects.
The messages are of the form:
<msg>
<id>1</id>
<action>stop</action>
</msg>
How can this be done?
You need to use the xsd.exe tool which gets installed with the Windows SDK into a directory something similar to:
C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin
And on 64-bit computers:
C:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin
And on Windows 10 computers:
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin
On the first run, you use xsd.exe and you convert your sample XML into a XSD file (XML schema file):
xsd yourfile.xml
This gives you yourfile.xsd, which in a second step, you can convert again using xsd.exe into a C# class:
xsd yourfile.xsd /c
This should give you a file yourfile.cs which will contain a C# class that you can use to deserialize the XML file you're getting - something like:
XmlSerializer serializer = new XmlSerializer(typeof(msg));
msg resultingMessage = (msg)serializer.Deserialize(new XmlTextReader("yourfile.xml"));
Should work pretty well for most cases.
Update: the XML serializer will take any stream as its input - either a file or a memory stream will be fine:
XmlSerializer serializer = new XmlSerializer(typeof(msg));
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString));
msg resultingMessage = (msg)serializer.Deserialize(memStream);
or use a StringReader:
XmlSerializer serializer = new XmlSerializer(typeof(msg));
StringReader rdr = new StringReader(inputString);
msg resultingMessage = (msg)serializer.Deserialize(rdr);
You have two possibilities.
Method 1. XSD tool
Suppose that you have your XML file in this location C:\path\to\xml\file.xml
Open Developer Command Prompt
You can find it in Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools
Or if you have Windows 8 can just start typing Developer Command Prompt in Start screen
Change location to your XML file directory by typing cd /D "C:\path\to\xml"
Create XSD file from your xml file by typing xsd file.xml
Create C# classes by typing xsd /c file.xsd
And that's it! You have generated C# classes from xml file in C:\path\to\xml\file.cs
Method 2 - Paste special
Required Visual Studio 2012+ with .Net Framework >= 4.5 as project target and 'Windows Communication Foundation' individual component installed
Copy content of your XML file to clipboard
Add to your solution new, empty class file (Shift+Alt+C)
Open that file and in menu click Edit > Paste special > Paste XML As Classes
And that's it!
Usage
Usage is very simple with this helper class:
using System;
using System.IO;
using System.Web.Script.Serialization; // Add reference: System.Web.Extensions
using System.Xml;
using System.Xml.Serialization;
namespace Helpers
{
internal static class ParseHelpers
{
private static JavaScriptSerializer json;
private static JavaScriptSerializer JSON { get { return json ?? (json = new JavaScriptSerializer()); } }
public static Stream ToStream(this string #this)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(#this);
writer.Flush();
stream.Position = 0;
return stream;
}
public static T ParseXML<T>(this string #this) where T : class
{
var reader = XmlReader.Create(#this.Trim().ToStream(), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document });
return new XmlSerializer(typeof(T)).Deserialize(reader) as T;
}
public static T ParseJSON<T>(this string #this) where T : class
{
return JSON.Deserialize<T>(#this.Trim());
}
}
}
All you have to do now, is:
public class JSONRoot
{
public catalog catalog { get; set; }
}
// ...
string xml = File.ReadAllText(#"D:\file.xml");
var catalog1 = xml.ParseXML<catalog>();
string json = File.ReadAllText(#"D:\file.json");
var catalog2 = json.ParseJSON<JSONRoot>();
Try this method to Convert Xml to an object. It is made for exactly what you are doing:
protected T FromXml<T>(String xml)
{
T returnedXmlClass = default(T);
try
{
using (TextReader reader = new StringReader(xml))
{
try
{
returnedXmlClass =
(T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
catch (InvalidOperationException)
{
// String passed is not XML, simply return defaultXmlClass
}
}
}
catch (Exception ex)
{
}
return returnedXmlClass ;
}
Call it using this code:
YourStrongTypedEntity entity = FromXml<YourStrongTypedEntity>(YourMsgString);
Simply Run Your Visual Studio 2013 as Administration ...
Copy the content of your Xml file..
Go to Visual Studio 2013 > Edit > Paste Special > Paste Xml as C# Classes
It will create your c# classes according to your Xml file content.
Just in case anyone might find this useful:
public static class XmlConvert
{
public static string SerializeObject<T>(T dataObject)
{
if (dataObject == null)
{
return string.Empty;
}
try
{
using (StringWriter stringWriter = new System.IO.StringWriter())
{
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(stringWriter, dataObject);
return stringWriter.ToString();
}
}
catch (Exception ex)
{
return string.Empty;
}
}
public static T DeserializeObject<T>(string xml)
where T : new()
{
if (string.IsNullOrEmpty(xml))
{
return new T();
}
try
{
using (var stringReader = new StringReader(xml))
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
}
catch (Exception ex)
{
return new T();
}
}
}
You can call it using:
MyCustomObject myObject = new MyCustomObject();
string xmlString = XmlConvert.SerializeObject(myObject);
myObject = XmlConvert.DeserializeObject<MyCustomObject>(xmlString);
You can generate class as described above, or write them manually:
[XmlRoot("msg")]
public class Message
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("action")]
public string Action { get; set; }
}
Then you can use ExtendedXmlSerializer to serialize and deserialize.
Instalation
You can install ExtendedXmlSerializer from nuget or run the following command:
Install-Package ExtendedXmlSerializer
Serialization:
var serializer = new ConfigurationContainer().Create();
var obj = new Message();
var xml = serializer.Serialize(obj);
Deserialization
var obj2 = serializer.Deserialize<Message>(xml);
This serializer support:
Deserialization xml from standard XMLSerializer
Serialization class, struct, generic class, primitive type, generic list and dictionary, array, enum
Serialization class with property interface
Serialization circular reference and reference Id
Deserialization of old version of xml
Property encryption
Custom serializer
Support XmlElementAttribute and XmlRootAttribute
POCO - all configurations (migrations, custom serializer...) are outside the class
ExtendedXmlSerializer support .NET 4.5 or higher and .NET Core. You can integrate it with WebApi and AspCore.
You can use xsd.exe to create schema bound classes in .Net then XmlSerializer to Deserialize the string : http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.deserialize.aspx
Simplifying Damian's great answer,
public static T ParseXml<T>(this string value) where T : class
{
var xmlSerializer = new XmlSerializer(typeof(T));
using (var textReader = new StringReader(value))
{
return (T) xmlSerializer.Deserialize(textReader);
}
}
I have gone through all the answers as at this date (2020-07-24), and there has to be a simpler more familiar way to solve this problem, which is the following.
Two scenarios... One is if the XML string is well-formed, i.e. it begins with something like <?xml version="1.0" encoding="utf-16"?> or its likes, before encountering the root element, which is <msg> in the question. The other is if it is NOT well-formed, i.e. just the root element (e.g. <msg> in the question) and its child nodes only.
Firstly, just a simple class that contains the properties that match, in case-insensitive names, the child nodes of the root node in the XML. So, from the question, it would be something like...
public class TheModel
{
public int Id { get; set; }
public string Action { get; set; }
}
The following is the rest of the code...
// These are the key using statements to add.
using Newtonsoft.Json;
using System.Xml;
bool isWellFormed = false;
string xml = = #"
<msg>
<id>1</id>
<action>stop</action>
</msg>
";
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
if (isWellFormed)
{
xmlDocument.RemoveChild(xmlDocument.FirstChild);
/* i.e. removing the first node, which is the declaration part.
Also, if there are other unwanted parts in the XML,
write another similar code to locate the nodes
and remove them to only leave the desired root node
(and its child nodes).*/
}
var serializedXmlNode = JsonConvert.SerializeXmlNode(
xmlDocument,
Newtonsoft.Json.Formatting.Indented,
true
);
var theDesiredObject = JsonConvert.DeserializeObject<TheModel>(serializedXmlNode);
I know this question is old, but I stumbled into it and I have a different answer than, well, everyone else :-)
The usual way (as the commenters above mention) is to generate a class and de-serialize your xml.
But (warning: shameless self-promotion here) I just published a nuget package, here, with which you don't have to. You just go:
string xml = System.IO.File.ReadAllText(#"C:\test\books.xml");
var book = Dandraka.XmlUtilities.XmlSlurper.ParseText(xml);
That is literally it, nothing else needed. And, most importantly, if your xml changes, your object changes automagically as well.
If you prefer to download the dll directly, the github page is here.
Create a DTO as CustomObject
Use below method to convert XML String to DTO using JAXB
private static CustomObject getCustomObject(final String ruleStr) {
CustomObject customObject = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(CustomObject.class);
final StringReader reader = new StringReader(ruleStr);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
customObject = (CustomObject) jaxbUnmarshaller.unmarshal(reader);
} catch (JAXBException e) {
LOGGER.info("getCustomObject parse error: ", e);
}
return customObject;
}
If you have the xsd of the xml message then you can generate c# classes using the .Net xsd.exe tool.
This .Net classes can then be used to generate the xml.
In addition to the other answers here you can naturally use the XmlDocument class, for XML DOM-like reading, or the XmlReader, fast forward-only reader, to do it "by hand".
Another way with an Advanced xsd to c# classes generation Tools : xsd2code.com. This tool is very handy and powerfull. It has a lot more customisation than the xsd.exe tool from Visual Studio. Xsd2Code++ can be customised to use Lists or Arrays and supports large schemas with a lot of Import statements.
Note of some features,
Generates business objects from XSD Schema or XML file to flexible C#
or Visual Basic code.
Support Framework 2.0 to 4.x
Support strong typed collection (List, ObservableCollection, MyCustomCollection).
Support automatic properties.
Generate XML read and write methods (serialization/deserialization).
Databinding support (WPF, Xamarin).
WCF (DataMember attribute).
XML Encoding support (UTF-8/32, ASCII, Unicode, Custom).
Camel case / Pascal Case support.
restriction support ([StringLengthAttribute=true/false], [RegularExpressionAttribute=true/false],
[RangeAttribute=true/false]).
Support large and complex XSD file.
Support of DotNet Core & standard
public string Serialize<T>(T settings)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StringWriter outStream = new StringWriter();
serializer.Serialize(outStream, settings);
return outStream.ToString();
}
I am using a class library which represents some of its configuration in .xml. The configuration is read in using the XmlSerializer. Fortunately, the classes which represent the .xml use the XmlAnyElement attribute at which allows me to extend the configuration data for my own purposes without modifying the original class library.
<?xml version="1.0" encoding="utf-8"?>
<Config>
<data>This is some data</data>
<MyConfig>
<data>This is my data</data>
</MyConfig>
</Config>
This works well for deserialization. I am able to allow the class library to deserialize the .xml as normal and the I can use my own XmlSerializer instances with a XmlNodeReader against the internal XmlNode.
public class Config
{
[XmlElement]
public string data;
[XmlAnyElement]
public XmlNode element;
}
public class MyConfig
{
[XmlElement]
public string data;
}
class Program
{
static void Main(string[] args)
{
using (Stream fs = new FileStream(#"c:\temp\xmltest.xml", FileMode.Open))
{
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
Config config = (Config)xser1.Deserialize(fs);
if (config.element != null)
{
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = (MyConfig)xser2.Deserialize(new XmlNodeReader(config.element));
}
}
}
I need to create a utility which will allow the user to generate a new configuration file that includes both the class library configuration as well my own configuration, so new objects will be created which were not read from the .xml file. The question is how can I serialize the data back into .xml?
I realize that I have to initially call XmlSerializer.Serialize on my data before calling the same method on the class library configuration. However, this requires that my data is represented by an XmlNode after calling Serialize. What is the best way to serialize an object into an XmlNode using the XmlSerializer?
Thanks,
-kevin
btw-- It looks like an XmlNodeWriter class written by Chris Lovett was available at one time from Microsoft, but the links are now broken. Does anyone know of an alternative location to get this class?
So you need to have your class contain custom configuration information, then serialize that class to XML, then make that serialized XML into an XML node: is that right?
Could you just take the string created by the XMLSerializer and wrap that in it's own XML tags?
XmlSerializer xs = new XmlSerializer(typeof(MyConfig));
StringWriter xout = new StringWriter();
xs.Serialize(xout, myConfig);
XmlDocument x = new XmlDocument();
x.LoadXml("<myConfig>" + xout.ToString() + "</myConfig>");
Now x is an XmlDocument containing one element, "<myconfig>", which has your serialized custom configuration in it.
Is that at all what you're looking for?
It took a bit of work, but the XPathNavigator route does work... just remember to call .Close on the XmlWriter, .Flush() doesn't do anything:
//DataContractSerializer serializer = new DataContractSerializer(typeof(foo));
XmlSerializer serializer = new XmlSerializer(typeof(foo));
XmlDocument doc = new XmlDocument();
XPathNavigator nav = doc.CreateNavigator();
XmlWriter writer = nav.AppendChild();
writer.WriteStartDocument();
//serializer.WriteObject(writer, new foo { bar = 42 });
serializer.Serialize(writer, new foo { bar = 42 });
writer.WriteEndDocument();
writer.Flush();
writer.Close();
Console.WriteLine(doc.OuterXml);
One solution is to serialize the inner object to a string and then load the string into a XmlDocument where you can find the XmlNode representing your data and attach it to the outer object.
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = new MyConfig();
myConfig.data = "My special data";
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XmlWriter xw = new XmlTextWriter(sw);
xser2.Serialize(xw, myConfig);
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
Config config = new Config();
config.data = "some new info";
config.element = doc.LastChild;
xser1.Serialize(fs, config);
However, this solution is cumbersome and I would hope there is a better way, but it resolves my problem for now.
Now if I could just find the mythical XmlNodeWriter referred to on several blogs!
At least one resource points to this as an alternative to XmlNodeWriter: http://msdn.microsoft.com/en-us/library/5x8bxy86.aspx. Otherwise, you could write MS using that form they have on the new MSDN Code Library replacement for GotDotNet looking for XmlNodeWriter.