How to serialize multiple objects into a existing XmlDocument in .Net/C#?
I have a XmlDocument, which already contains data. I have multiple objects. Now I want to s
This will serialize objects and append them to a XmlDocument. While de-/serializing the code will resolve the namespaces. @Alex: Thanks for the example with XPathNavigator.
void test2()
{
XmlDocument doc = new XmlDocument();
XmlNode root = doc.AppendChild(doc.CreateElement("root"));
doc.DocumentElement.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
doc.DocumentElement.SetAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
serializeAppend(root, new object[] { 1, "two", 3.0 }); // serialize object and append it to XmlNode
var obj = deserialize<object[]>(root.ChildNodes[0]); // deserialize XmlNode to object
}
T deserialize<T>(XmlNode node)
{
XPathNavigator nav = node.CreateNavigator();
using (var reader = nav.ReadSubtree())
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(reader);
}
}
void serializeAppend(XmlNode parentNode, object obj)
{
XPathNavigator nav = parentNode.CreateNavigator();
using (var writer = nav.AppendChild())
{
var serializer = new XmlSerializer(obj.GetType());
writer.WriteWhitespace("");
serializer.Serialize(writer, obj);
writer.Close();
}
}
The code below will fulfill the requirement in the OP, to have a clean XML. It will remove all tributes from all elements, but it will add a type
attribute to the anyType
elements, so the original type could still be distinguish for each element.
static void Main(string[] args)
{
object[] components = new object[] { new Component_1(), new Component_1() };
var doc = new XmlDocument();
doc.Load("source.xml");
var project = doc.GetElementsByTagName("project")[0];
var nav = project.CreateNavigator();
var emptyNamepsaces = new XmlSerializerNamespaces(new[] {
XmlQualifiedName.Empty
});
foreach (var component in components)
{
using (var writer = nav.AppendChild())
{
var serializer = new XmlSerializer(component.GetType());
writer.WriteWhitespace("");
serializer.Serialize(writer, component
, emptyNamepsaces
);
writer.Close();
}
}
foreach (XmlNode node in doc.GetElementsByTagName("anyType"))
{
string attributeType = "";
foreach (XmlAttribute xmlAttribute in node.Attributes)
{
if (xmlAttribute.LocalName == "type")
{
attributeType=xmlAttribute.Value.Split(':')[1];
}
}
node.Attributes.RemoveAll();
node.CreateNavigator().CreateAttribute("","type","",attributeType);
}
doc.Save("output.xml");
}
If you want to deserialize the XML, you'll have to create a dictionary:
static Dictionary<string, Type> _typeCache;
add the expected XML types mapped to corresponding Type
values to it:
_typeCache = new Dictionary<string, Type>();
_typeCache.Add("string", typeof(System.String));
_typeCache.Add("int", typeof(System.Int32));
_typeCache.Add("dateTime", typeof(System.DateTime));
and replace each XmlNode
in the array by converting it to it's expected type accordingly:
Component_1 c = Deserialize<Component_1>(project.ChildNodes[0].OuterXml);
for (int i = 0; i < c.objectArray.Length; i++)
{
var type = _typeCache[(((System.Xml.XmlNode[])(c.objectArray[i]))[0]).Value];
var item = Convert.ChangeType((((System.Xml.XmlNode[])(c.objectArray[i]))[1]).Value, type);
c.objectArray[i] = item;
}
Console.WriteLine(c.objectArray[0].GetType()); // -> System.String