Posted By: PeterH | Jun 24th, 2005 @ 8:39 AM
page 1 of 1
Comments: 22 | Views: 8526
PeterH
PeterH
Iomesus
I'm trying to do some XML Serialization for a class that I have. It is supposed to store the information of cars. This is the result that I get when I create one object from the class:

  <?xml version="1.0" encoding="utf-8" ?>
   <DateSubmitted>24/06/2005</DateSubmitted>
   <Make>Ford1</Make>
   <Model>Mondeo</Model>
   <Description>Foo</Description>
   <ImagePath>None</ImagePath>
   <Year>1995</Year>
   <InitialMileage>33000</InitialMileage>
   <Sold>false</Sold>
 </CarData>


And this is the code that creates it:


namespace vintageMotors

{

[XmlRoot("CarData")]

public class Car

{

// Fields

private string _dateSubmitted;

private string _make;

private string _model;

private string _description;

private string _imagePath;

private int _year;

private int _initialMileage;

private bool _sold;

// Constructor

public Car()

{

_imagePath = "None";

_sold = false;

_dateSubmitted = DateTime.Now.ToShortDateString();

}

// Properties

public string DateSubmitted

{

get { return _dateSubmitted; }

set { _dateSubmitted = value; }

}

public string Make

{

get { return _make; }

set { _make = value; }

}

public string Model

{

get { return _model; }

set { _model = value; }

}

public string Description

{

get { return _description; }

set { _description = value; }

}

public string ImagePath

{

get { return _imagePath; }

set { _imagePath = value; }

}

public int Year

{

get { return _year; }

set { _year = value; }

}

public int InitialMileage

{

get { return _initialMileage; }

set { _initialMileage = value; }

}

public bool Sold

{

get { return _sold; }

set { _sold = value; }

}

}

}


And this:

Car newCar = new Car();

newCar.Make = "Ford1";

newCar.Model = "Mondeo";

newCar.Year = 1995;

newCar.InitialMileage = 33000;

newCar.Description = "Foo";

XmlSerializer s = new XmlSerializer(typeof(Car));

TextWriter w = new StreamWriter("DataStore.xml");

s.Serialize(w, newCar);

w.Close();


However, I want to know how I can change the code so that it can hold multiple objects/cars. I would prefer to have this sort of structure for my XML Document:

  <?xml version="1.0" encoding="utf-8" ?>
    <CarData  xmlns:xsi=http://www.w3.org/2001/XMLSchema- instance  xmlns:xsd=http://www.w3.org/2001/XMLSchema>
 <Car DateSubmitted="24/06/2005">
    <Make>Ford1</Make>
    <Model>Mondeo</Model>
    <Description>Foo</Description>
    <ImagePath>None</ImagePath>
    <Year>1995</Year>
    <InitialMileage>33000</InitialMileage>
    <Sold>false</Sold>
 </Car>
 <Car DateSubmitted="24/06/2005">
   <Make>Ford1</Make>
   <Model>Mondeo</Model>
   <Description>Foo</Description>
   <ImagePath>None</ImagePath>
   <Year>1995</Year>
   <InitialMileage>33000</InitialMileage>
   <Sold>false</Sold>
</Car>
<Car DateSubmitted="24/06/2005">
  <Make>Ford1</Make>
  <Model>Mondeo</Model>
  <Description>Foo</Description>
  <ImagePath>None</ImagePath>
  <Year>1995</Year>
  <InitialMileage>33000</InitialMileage>
  <Sold>false</Sold>
</Car>
   </CarData>


I hope you understand what I mean, thanks in advance!
Tyler Brown
Tyler Brown
Bullets change governments far surer than votes.
To serialize more than one car object to the file, you should be able to just do the following:
Car car1 = new Car();<br>

car1.Make = "Dodge";<br>

car1.Model = "Viper";<br>

car1.Year = "2005";<br>

car1.InitialMileage = "0";<br>

car1.Description = "Dream Car";<br>
<br>
Car car2 = new Car();<br>

car2.Make = "Mitsubishi";<br>

car2.Model = "Eclipse";<br>

car2.Year = "2005";<br>

car2.InitialMileage = "0";<br>

car2.Description = "Dream Car";<br>
<br>
XmlSerializer s = new XmlSerializer(typeof(Car));<br>
TextWriter w = new StreamWriter("DataStore.xml");<br>
s.Serialize(w, car1);<br>
s.Serialize(w, car2);<br>
w.Close();

This should serialize both car objects to the DataStore.xml file. I've never attempted this before, but I believe this should work. If I'm wrong someone will correct me.
Peter,

You would need to create a 'CarCollection' object that holds a collection of your 'Car' objects. Then you would serialize the whole collection. Are you familiar with creating a class that inherits from CollectionBase?

Somebody please correct me if you cannot serialize a collection with the XMLSerializer...It's been a while since I've used it.

Another option would be to store your car data in a DataSet/DataTable and use the DataSet.WriteXML feature....a lot more complicated xml with this option though.....

Regards,

Chris
Well are you using .net 1.1 or .net 2.0 ? because You can serialize List<T> generics and thus could create a collection of stronly types cars and you would not have to go through the whole mess of creating the inherited class and use the whole getdataobject stuff.
then just use a List<Car> and add the cars to that and then serialize the list and since I am one of those people who enjoys looking at examples I went ahead and created one for you based upon what u had.

Code
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
PeterH wrote:
I'm using the .net Framework 2.0.

Fill a List<Car> and serialize it. Problem solved. Smiley
If you grab that code I linked to in my post it will show you.
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
PeterH wrote:
Sven Groot wrote:
Fill a List<Car> and serialize it. Problem solved. Smiley



What is the syntax for doing so, sorry I've never used this before.

Thanks in advance.

List<Car> carList = new List<Car>();<BR>carList.Add(car1);<BR>carList.Add(car2);<BR><BR>XmlSerializer s = new XmlSerializer(typeof(List<Car>));<BR>using( StreamWriter writer = new StreamWriter("datastore.xml") )<BR>{<BR>   s.Serialize(writer, carList);<BR>}
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
PeterH wrote:

Ahhh. now I understand, thanks both of you.

Wacko: How could I change the code you posted so that it doesn't over write the XML file. I want it to add to the end.

Thanks.


You cannot append to an XML file, because it wouldn't be a valid XML file anymore. An XML file can have only one root element, and if you append to an existing XML file, you'd be adding another one. That's why the first attempt (serializing two cars to the same stream) didn't work.

There are several ways to solve this, but the easiest way is by first deserializing the existing xml file into a List<Car>, adding the new items to the end and then serializing back out, overwriting the original file.
Peter I went ahead and updated my code to give u an idea of how it works

Code
Hello,

I know this thread is a little old, but it covered some things pertaining to exactly what I am trying to do with Visual Studio 2005 via VB.NET.

The problem I am having is that after writing the XML for the first object, the serializer ALWAYS closes that and then creates another top level header, then it writes the rest of the objects' data.

As a test I even modified my program to store only objects of the same type and it did not work, then I put the objects into a collection (arraylist) and serialized the collection but it did the same thing.

Anybody know why this is happening other than to torment me? Wink

Here is an example - in this case both objects of the same type are added to a collection called 'col' and then that collection is serialized:

<?xml version="1.0"?>
<ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <anyType xsi:type="ScreenData">
    <ScreenTitle>Main</ScreenTitle>
    <IsMain>true</IsMain>
    <BackgroundImageFilename>skins\default\TexturedWindowsXP.jpg</BackgroundImageFilename>
    <BackgroundMode>Undefined</BackgroundMode>
    <Screen_Text />
    <Screen_BackgroundImage />
    <Screen_BackgroundImageLayout>0</Screen_BackgroundImageLayout>
    <Screen_Width>0</Screen_Width>
    <Screen_Height>0</Screen_Height>
  </anyType>
</ArrayOfAnyType><?xml version="1.0"?>
<ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <anyType xsi:type="ScreenData">
    <ScreenTitle>Main</ScreenTitle>
    <IsMain>true</IsMain>
    <BackgroundImageFilename>skins\default\TexturedWindowsXP.jpg</BackgroundImageFilename>
    <BackgroundMode>Undefined</BackgroundMode>
    <Screen_Text />
    <Screen_BackgroundImage />
    <Screen_BackgroundImageLayout>0</Screen_BackgroundImageLayout>
    <Screen_Width>0</Screen_Width>
    <Screen_Height>0</Screen_Height>
  </anyType>
  <anyType xsi:type="ScreenData">
    <ScreenTitle>Lighting</ScreenTitle>
    <IsMain>false</IsMain>
    <BackgroundImageFilename>Skins\Default\TexturedWindowsXP.jpg</BackgroundImageFilename>
    <BackgroundMode>Undefined</BackgroundMode>
    <Screen_Text />
    <Screen_BackgroundImage />
    <Screen_BackgroundImageLayout>0</Screen_BackgroundImageLayout>
    <Screen_Width>0</Screen_Width>
    <Screen_Height>0</Screen_Height>
  </anyType>
</ArrayOfAnyType>


Notice how it did the first object, then closed the XML and opened it again and wrote both objects.

If I create another class to hold the objects and add that to the collection, then I only get the two objects that I am expecting, but again it is done with two sets of XML headers.
Sorry for the rudeness of this, but...

BUMP
ZippyV
ZippyV
Fired Up
Use List instead of ArrayList.
Thank you for the suggestion - it did not help though.  Whether a list or an arraylist collection, it always dumps the first object, then does the header again and then dumps both objects.

Yeah, it's pretty frustrating. Sad
ZippyV
ZippyV
Fired Up
The way I always do it is to create a main class that holds the array of your other classes. Using the serializer, you serialize the main class.
Apparently the XML writer is not smart enough to start and end the document on its own, yet it can keep track of the fact that it has been started if you start it yourself....

I used (XML Writer).WriteStartDocument before I wrote the same data I was writing before, but somehow that fixed it.  (I end it manually as well).

I thought the writer was suppose to take care of that?

Anyway, problem solved, just not in an obvious way as is usually the case.
ZippyV
ZippyV
Fired Up

My code:
Serializer method:
    Public Sub SaveLibrary(ByVal Path As String)
        Dim xs As New XmlSerializer(GetType(Library.library))
        Dim fs As New FileStream(Path, FileMode.OpenOrCreate)
        Dim writer As New XmlTextWriter(fs, Encoding.UTF8)

        xs.Serialize(writer, lLibrary)
        writer.Close()
    End Sub

-----------------------------

the Library class (generated from xml file using xsd.exe - Replaced ArrayList with List(Of T)):

    <System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42"), _
     System.SerializableAttribute(), _
     System.Diagnostics.DebuggerStepThroughAttribute(), _
     System.ComponentModel.DesignerCategoryAttribute("code"), _
     System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True), _
     System.Xml.Serialization.XmlRootAttribute([Namespace]:="", IsNullable:=False)> _
    Partial Public Class library

        Private minisceneField As List(Of libraryMiniscene)
        Private authorField As String
        Private nameField As String
        Private versionField As String
        Private idField As String

        <System.Xml.Serialization.XmlElementAttribute("miniscene")> _
        Public Property miniscene() As List(Of libraryMiniscene)
            Get
                Return Me.minisceneField
            End Get
            Set(ByVal value As List(Of libraryMiniscene))
                Me.minisceneField = value
            End Set
        End Property

        <System.Xml.Serialization.XmlAttributeAttribute()> _
        Public Property author() As String
            Get
                Return Me.authorField
            End Get
            Set(ByVal value As String)
                Me.authorField = value
            End Set
        End Property

        <System.Xml.Serialization.XmlAttributeAttribute()> _
        Public Property name() As String
            Get
                Return Me.nameField
            End Get
            Set(ByVal value As String)
                Me.nameField = value
            End Set
        End Property

        <System.Xml.Serialization.XmlAttributeAttribute()> _
        Public Property version() As String
            Get
                Return Me.versionField
            End Get
            Set(ByVal value As String)
                Me.versionField = value
            End Set
        End Property

        <System.Xml.Serialization.XmlAttributeAttribute()> _
        Public Property id() As String
            Get
                Return Me.idField
            End Get
            Set(ByVal value As String)
                Me.idField = value
            End Set
        End Property
    End Class

Missing libraryMiniscene and frame class
----------------------------
Resulting xml file:

<?xml version="1.0" encoding="utf-8"?>
<library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" author="ZippyV" name="Testy" version="1" id="b9291927-70e4-4127-86ca-ed3bccd261bd">
 <miniscene id="1" name="Testy 1">
  <frame number="1">
   <duration>200</duration>
   <data>170</data>
  </frame>
  <frame number="2">
   <duration>200</duration>
   <data>85</data>
  </frame>
 </miniscene>
<miniscene id="2" name="Testy 2">
  <frame number="1">
   <duration>200</duration>
   <data>170</data>
  </frame>
  <frame number="2">
   <duration>200</duration>
   <data>85</data>
  </frame>
 </miniscene>
</library

page 1 of 1
Comments: 22 | Views: 8526
Microsoft Communities