C #, insert strongly typed object into XML document as element

I have an XML document that contains the following structure:

More or less a collection of events:

<Events>
  <Event>
    <DateTime></DateTime>
    <EventType></EventType>
    <Result></Result>
    <Provider></Provider>
    <ErrorMessage></ErrorMessage>
    <InnerException></InnerException>
  </Event>
</Events>

      

In C #, I have a persistent Event object:

Now, given that the document already exists and is saved in the file ... I call:

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(dataPath);

      

Now how to add a new event item to events?

I have a strongly typed Event element in my C # code and want it to be inserted into the Events collection in an XML object as the last child.

I think this is what I am really asking: https://stackoverflow.com/questions/1457033/c-insert-a-strongly-typed-object-as-node-in-existing-xml-document

+2


source to share


6 answers


Just put in the code using XmlDocument. You can add a class that transforms or inserts into the document you are about to save.

This is based on the .net 2.0 limitation and what you said in those comments:



  • @Fred, I want to try to minimize the write time, so the reason not to write everything at once, the less time to write in this application, the less chance of file corruption. - JL 16 min ago
  • Why do you think you have a lot of chances for file corruption? - Frederik Gheysels 9 min ago
  • From the existing code test results, I already use serialization in general.
+1


source


Take a look at the Xml Serialization attributes.

You can do it:

[XmlRoot("Event")]
public class Event
{

    [XmlElement("DateTime")]
    public string DateTime 
    {
        get;
        set;
    }

    [XmlElement("EventType")]
    public EnumReportingEventType EventType
    {
        get;
        set;
    }

    [XmlElement("Result")]
    public EnumReportingResult Result
    {
        get;
        set;
    }

    [XmlElement("Provider")]
    public string Provider
    {
        get;
        set;
    }

    [XmlElement("ErrorMessage")]
    public string ErrorMessage
    {
        get;
        set;
    }

    [XmlElement("InnerException")]
    public string InnerException
    {
        get;
        set;
    }
}

      



In fact, if the properties of your class have the same name as the elements in your Xml, then you don't need to use the XmlElement attributes.

Then you can use XmlSerializer to serialize and deserialize.

Edit: Wouldn't it be better then to create a type that represents the whole type that is stored in the existing xml?
Deserialize it, give a value for an extra property and serialize it back?

+3


source


If you are using .Net 3.5 you can use Linq for XML, something like the following will work

XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment("Event document"),
new XElement("Events", 
    new XElement ("Event",
        new XElement("DateTime", event.DateTime),
        new XElement("EventType", event.EventType),
        new XElement("Result", event.Result),
        new XElement("Provider", event.Provider),
        new XElement("ErrorMessage", event.ErrorMessage),
        new XElement("InnerException", event.InnerException)
    )
 ));


doc.Save(@"c:\sample.xml");

      

If you have an existing xml document you want to add to somthing as the following is required.

XDocument doc = XDocument.Load(@"c:\sample.xml");
XElement events = doc.Element(XName.Get("Events"));
events.Add(new XElement ("Event",
        new XElement("DateTime", event.DateTime),
        new XElement("EventType", event.EventType),
        new XElement("Result", event.Result),
        new XElement("Provider", event.Provider),
        new XElement("ErrorMessage", event.ErrorMessage),
        new XElement("InnerException", event.InnerException)
));

doc.Save(@"c:\sample.xml");

      

+1


source


Insert an XmlElement next to the Event class, for example:

[System.Xml.Serialization.XmlAnyElementAttribute()]
public System.Xml.XmlElement Any { get; set }

      

You can call it whatever you want as long as it has "XmlAnyElementAttribute" on it.

To serialize a strongly typed object into this field, you can use something like the following:

MyParentObject parent = new MyParentObject(){ ... };

MyObject obj = new MyObject(){ /*... initialize*/ };
XmlSerializer ser = new XmlSerializer(typeof(MyObject));
XmlDocument doc = new XmlDocument();

using (StringWriter sw = new StringWriter())
{
    ser.Serialize(sw, obj);
    doc.LoadXml(sw.ToString());
}

parent.Any = (XmlElement)doc.DocumentElement;

      

Serialized XML will add nicely to your class, this event includes correct namespaces.

+1


source


Assuming your class Event

can already be serialized the way you want using XmlSerializer

, you can do the following:

XmlSerializer ser = new XmlSerializer(typeof(Event));

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(dataPath);

Event evt = ...;

XmlDocument evtDoc = new XmlDocument();
using (XmlWriter writer = evtDoc.CreateNavigator().AppendChild())
{
     ser.Serialize(writer, evt);
}
XmlNode evtNode = evtDoc.RemoveChild(evtDoc.DocumentElement);

XmlNode events = xmlDoc.SelectSingleNode("/Events");
events.AppendChild(evtNode);

      

+1


source


What you want to do is something like:

doc.ChildNode[0].AppendChild(MethodToReturnADeserializedObject(event));

      

Create a method to deserialize the event object in the xml node. Then use AppendChild to insert this as the last element among its child nodes.

0


source







All Articles