Proper way to read xml using xmlReader

Wednesday, November 4, 2015

I have the following class for reading/writing my serializable classes



/// <summary>
/// Contains the logic for streaming extensions.
/// </summary>
public static class StreamExtensions
{
/// <summary>
/// Serialize an object.
/// </summary>
/// <typeparam name="T">The type of the object that gets serialized.</typeparam>
/// <param name="stream">The stream to which the bytes will be written.</param>
/// <param name="serializableObject">The object that gets serialized.</param>
public static void SerializeObject<T>(this Stream stream, T serializableObject) where T : IXmlSerializable
{
var writerSettings = new XmlWriterSettings();

writerSettings.Indent = true;
writerSettings.IndentChars = " "; // 4 spaces
writerSettings.Encoding = Encoding.UTF8;

using (var xmlWriter = XmlWriter.Create(stream, writerSettings))
{
serializableObject.WriteXml(xmlWriter);
}

stream.Close();
}

/// <summary>
/// Deserialize a stream and return the object.
/// </summary>
/// <typeparam name="T">The type of the object that returns from the deserialization.</typeparam>
/// <param name="stream">The stream which contains the bytes to deserialize.</param>
/// <returns>The object recovered.</returns>
public static T DeserializeObject<T>(this Stream stream) where T : IXmlSerializable
{
using (var xmlTextReader = XmlReader.Create(stream))
{
var serializer = new XmlSerializer(typeof(T));
T result = (T)serializer.Deserialize(xmlTextReader);
stream.Close();
return result;
}
}
}


Here are 2 serializable test classes:



/// <summary>
/// A serializable class for testing purposes.
/// </summary>
public class SerializableXmlTestParent : IXmlSerializable
{
#region Fields
private string mTestString = string.Empty;
private SerializableXmlTestChild mTestChild = new SerializableXmlTestChild();
#endregion

#region Properties
/// <summary>
/// Gets or sets a test string.
/// </summary>
/// <value>The configuration for this simulation.</value>
public string TestString
{
get
{
return mTestString;
}

set
{
mTestString = value;
}
}

/// <summary>
/// Gets or sets the child element.
/// </summary>
/// <value>The configuration for this simulation.</value>
public SerializableXmlTestChild TestChild
{
get
{
return mTestChild;
}

set
{
mTestChild = value;
}
}
#endregion

#region XML serialization region
/// <summary>
/// Write the extra information to an XML stream.
/// </summary>
/// <param name="writer">Writer to write to.</param>
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement(MethodBase.GetCurrentMethod().DeclaringType.Name);
writer.WriteAttributeString("TestString", this.TestString);
this.TestChild.WriteXml(writer);
writer.WriteEndElement();
}

/// <summary>
/// Read the extra information from an XML stream.
/// </summary>
/// <param name="reader">Reader to read from.</param>
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
this.TestString = reader.GetAttribute("TestString");
reader.ReadStartElement();
reader.MoveToContent();
this.TestChild.ReadXml(reader);
}

/// <summary>
/// This method is reserved when implementing the IXmlSerializable interface.
/// </summary>
/// <returns>An XmlSchema that describes the XML representation of the
/// object that is produced by the WriteXml method and consumed by the
/// ReadXml method.</returns>
public XmlSchema GetSchema()
{
return null;
}
#endregion
}


and



/// <summary>
/// A serializable class for testing purposes.
/// </summary>
public class SerializableXmlTestChild : IXmlSerializable
{
#region Fields
private string mTestString = string.Empty;
#endregion

#region Properties
/// <summary>
/// Gets or sets the configuration for this simulation.
/// </summary>
/// <value>The configuration for this simulation.</value>
public string TestString
{
get
{
return mTestString;
}

set
{
mTestString = value;
}
}
#endregion

#region XML serialization region
/// <summary>
/// Write the extra information to an XML stream.
/// </summary>
/// <param name="writer">Writer to write to.</param>
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement(MethodBase.GetCurrentMethod().DeclaringType.Name);
writer.WriteAttributeString("TestString", this.TestString);
writer.WriteEndElement();
}

/// <summary>
/// Read the extra information from an XML stream.
/// </summary>
/// <param name="reader">Reader to read from.</param>
public void ReadXml(XmlReader reader)
{
this.TestString = reader.GetAttribute("TestString");
}

/// <summary>
/// This method is reserved when implementing the IXmlSerializable interface.
/// </summary>
/// <returns>An XmlSchema that describes the XML representation of the
/// object that is produced by the WriteXml method and consumed by the
/// ReadXml method.</returns>
public XmlSchema GetSchema()
{
return null;
}
#endregion
}


The way I am currently reading (and writing) the classes works, though I do not know if it is the nicest way to do it.



take for example the ReadXML method of the child class:



    public void ReadXml(XmlReader reader)
{
this.TestString = reader.GetAttribute("TestString");
}


There is no reader.MoveToContent(), no reader.readStartElement() no reader.ReadEndElement().



In the parent I do use a ReadStartElement to get to the child element, but should i do that in parent?



What is the proper way to read a xml document like this:



<?xml version="1.0" encoding="utf-8"?>
<SerializableXmlTestParent TestString="Test">
<SerializableXmlTestChild TestString="otherString" />
</SerializableXmlTestParent>


Just to clarify the code does work but I feel like it's not how it is supposed to be written. xmlReader has all these nice methods and i use virtually none so is there any way to improve the code? Do I need to check more if I'm actually on the right element?



I would expect the good code to look somewhat like this because this is (about) the same way I write the xml (but this does not work for me)



ReadXml() of parent



public void ReadXml(XmlReader reader)
{
reader.ReadStartElement();
reader.MoveToContent();
this.TestString = reader.GetAttribute("TestString");
this.TestChild.ReadXml(reader);
reader.ReadEndElement();
}


ReadXml() of child:



public void ReadXml(XmlReader reader)
{
reader.ReadStartElement();
reader.MoveToContent();
this.TestString = reader.GetAttribute("TestString");
reader.ReadEndElement();
}

0 comments:

Post a Comment