Daily Archives: January 21, 2014
XML (part 3, basics, advanced), serialize
Posted by Bastian M.K. Ohta
We are still working with the environment of part 2. We are using the embedded file “Walmart.xml”.
In part 1 we were loading an XML file the following way:
public static void LoadXml() { string lDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\"; string lFile = lDesktopPath + "Walmart.xml"; XDocument lXDocument = XDocument.Load(lFile); // food (using WmItem) WmItem[] lFood = (from lData in lXDocument.Descendants("Walmart").Descendants("food") select new WmItem( lData.Element("name").Value, double.Parse(lData.Element("price").Value), lData.Element("description").Value) ).ToArray(); foreach (WmItem lItem in lFood) Console.WriteLine(lItem); Console.WriteLine(); // electronic (quick and dirty, using var) var lElectronic = from lData in lXDocument.Descendants("Walmart").Descendants("electronic") select lData; foreach (var lItem in lElectronic) { Console.WriteLine(lItem); Console.WriteLine(); Console.WriteLine(lItem.Element("name").Value); Console.WriteLine(lItem.Element("price").Value); Console.WriteLine(lItem.Element("description").Value); } Console.ReadLine(); } //
LINQ queries were parsing the XML file and initialized the objects.
Well, there is a more direct way out there. Let the .Net framework do the dirty job. Just make use of properties. Here are some of them:
Serializable
Tells that data can be arranged in a sequence. The object can then be sent across networks or be saved.
XmlRoot
This is the root of all elements. Each XML file can only have one root element. Compared to hard disk drives on your computer it would be the “C:” directory.
XmlElement
A field or property of an object becomes an XML element during the conversion.
XmlText
A text field. Only one instance of the XmlTextAttribute can be applied in a class.
XmlAttribute
This attribute is self-explanatory. Use it whenever you want to add attributes to XML items.
Add the following two classes in your project. They define the structure of your XML file. You do not have to use attributes for all types. Attributes are optional. This means you can add as many non-Xml-Elements to a class as you like. They are simply ignored during (de-)serialization processes.
[Serializable] [XmlRoot("Walmart", Namespace = "")] public class WalmartWorld { [XmlElement("food")] public List<WalmartItem> Food { get; set; } [XmlElement("electronic")] public List<WalmartItem> Electronic { get; set; } [XmlText] public string Text { get; set; } } // class [Serializable] [XmlRoot("Walmart", Namespace = "")] public class WalmartItem { [XmlAttribute("attr")] public string Attribute { get; set; } [XmlElement("name")] public string Name { get; set; } [XmlElement("price")] public double Price { get; set; } [XmlElement("description")] public string Description { get; set; } [XmlElement("somethingElse")] public string SomethingElse { get; set; } public override string ToString() { return Name.PadRight(12) + Price.ToString("#,##0.00").PadLeft(8) + " " + Description + (string.IsNullOrEmpty(SomethingElse) ? string.Empty : (" !!! => " + SomethingElse)); } // } // class
Step one is to load our embedded file “Walmart.xml” using above classes. The objects will be created for you. There is no need for further parsing or instanciating.
public static WalmartWorld LoadObjects() { string lPath = "DemoApp.XmlFiles.Walmart.xml"; Assembly lAssembly = Assembly.GetExecutingAssembly(); using (Stream lStream = lAssembly.GetManifestResourceStream(lPath)) { XmlSerializer lXmlSerializer = new XmlSerializer(typeof(WalmartWorld)); using (StreamReader lStreamReader = new StreamReader(lStream)) { return lXmlSerializer.Deserialize(lStreamReader) as WalmartWorld; } } } //
Above method returns fully initialized classes. Nice, eh?
The code is amazingly short. Let’s convert and save objects on the desktop with this code:
public static void SaveObjects(WalmartWorld xWalmartWorld) { string lDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\"; string lFile = lDesktopPath + "Walmart2.xml"; var lXmlSerializer = new XmlSerializer(typeof(WalmartWorld)); using (var lStreamWriter = new StreamWriter(lFile)) { lXmlSerializer.Serialize(lStreamWriter, xWalmartWorld); } } //
Again, the code could not be shorter.
You can test above methods with the following:
public static void SerializerTest() { // load WalmartWorld lWalmartWorld = LoadObjects(); if (lWalmartWorld == null) return; // error // print results foreach (WalmartItem f in lWalmartWorld.Food) Console.WriteLine(f.ToString()); foreach (WalmartItem e in lWalmartWorld.Electronic) Console.WriteLine(e.ToString()); // add some stuff lWalmartWorld.Text = "Luis Armstrong had a fabulous voice."; lWalmartWorld.Food[2].Attribute = "What a wonderful world."; // save SaveObjects(lWalmartWorld); Console.ReadLine(); } //
Have a look at your file “Walmart2.xml”, which was saved onto your desktop. It is not exactly the same as “Walmart.xml”. We added some text and attributes.
Add “Walmart2.xml” to your Visual Studio Solution Explorer and see that you can load it without any trouble. Remember to set the file property “Build Action” to “Embedded Resource”.
You can also use a file stream to load the XML file. The program just gets shorter again, not longer:
public static WalmartWorld LoadXmlAsObject() { string lDesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + @"\"; string lFile = lDesktopPath + "Walmart2.xml"; XmlSerializer lXmlSerializer = new XmlSerializer(typeof(WalmartWorld)); using (StreamReader lStreamReader = new StreamReader(lFile)) { return lXmlSerializer.Deserialize(lStreamReader) as WalmartWorld; } } //
Posted in Advanced, Basic, C#, XML
Tags: C#, C-sharp, CSharp, embedded, I/O, LINQ, programming, serialize, Source code, XML, XmlDocument