Serialization from Xml into Object
First, I should state that this post refers to a Silverlight 4 application. Silverlight 4 seems to have a cut-down version of the Serialization model.
I have an XML file in the following format:
Code:
<?xml version="1.0" standalone="yes"?>
<TeamTable>
<TeamRow Id="1" Name="Arsenal" />
<TeamRow Id="2" Name="Aston Villa" />
<TeamRow Id="3" Name="Blackburn Rovers" />
<TeamRow Id="4" Name="Bolton Wanderers" />
<TeamRow Id="5" Name="Chelsea" />
...
</TeamTable>
I read the XML into an XDocument and then call the Load(...) member on my TeamTable Class:
Code:
public class TeamTable : List<TeamRow>
{
public void Load(XDocument document)
{
foreach (XElement element in document.Descendants("TeamRow"))
this.Add(TeamRow.Load(element));
}
}
For each of the TeamRow elements in the document, this function calls the Load(...) member of my TeamRow class:
Code:
[DataContract]
public class TeamRow
{
[DataMember]
public Int32 Id { get; set; }
[DataMember]
public String Name { get; set; }
public TeamRow() { }
public static TeamRow Load(XElement element)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(TeamRow));
using (XmlReader reader = element.CreateReader())
{
return serializer.ReadObject(reader) as TeamRow;
}
}
}
All appears to be well, the first element passed to this function contains
<TeamRow Id="1" Name="Arsenal" />
as I would expect.
However the ReadObject(...) function is throwing the following exception.
Code:
Expecting element 'TeamRow' from namespace 'http://schemas.datacontract.org/2004/07/...'..
Encountered 'Element' with name 'TeamRow', namespace".
This is my first attempt at this type of serialization. Can anyone help me fix the exception?
Re: Serialization from Xml into Object
try changing your DataContractSerializer to this:
Code:
DataContractSerializer serializer = new DataContractSerializer(typeof(TeamRow), "TeamRow", "");
Re: Serialization from Xml into Object
Thanks Joe.
That has cleared the exception and now I have a list of 20 (the number of teams) TeamRow's. However, each entry in the list has:
Id = 0
Name = null
I'll continue on with my trial and error to see if I can work out why, but any further help is appreciated.
Re: Serialization from Xml into Object
Debugging confirms that the 'set' accessor on the TeamRow.Id property NEVER gets called.
I was assuming that the DataContractSerializer would call those to set their values during the ReadObject() call.
Still stuck.
1 Attachment(s)
Re: Serialization from Xml into Object
Does Silverlight support the XmlSerializer class?
If so, create a couple of classes with Xml attributes:
Code:
namespace CG
{
#region Using Directives
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
#endregion Using Directives
///<summary>
/// Serialization class used to read the teamtable
///</summary>
[Serializable]
[XmlType( AnonymousType = true )]
[XmlRoot( ElementName = "TeamTable", Namespace = "", IsNullable = false )]
publicclassTeams
{
///<summary/>
publicstaticTeams Open( string configFile )
{
var serializer = newXmlSerializer( typeof( Teams ) );
using ( var reader = XmlReader.Create( configFile ) )
{
return ( Teams ) serializer.Deserialize( reader );
}
}
///<remarks/>
[XmlElement( "TeamRow", IsNullable = false )]
publicTeam [ ] Rows
{
get
{
return _rows.ToArray( );
}
set
{
if ( null == _rows )
{
_rows = newList<Team>( );
}
_rows.AddRange( value );
}
}
privateList<Team> _rows = newList<Team>( );
}
///<remarks/>
[Serializable]
[XmlType( AnonymousType = true )]
publicclassTeam
{
///<remarks/>
[XmlAttribute( AttributeName = "Id" )]
publicint Id { get { return _id; } set { _id = value; } }
///<remarks/>
[XmlAttribute( AttributeName = "Name" )]
publicstring Name { get { return _name; } set { _name = value; } }
privateint _id;
privatestring _name;
}
}
Then loading up the xml is:
Code:
var teamList = newList<Team>( );
// Loads the xml into a Teams instance
var teams = Teams.Open("teams.xml");
// Retrieve the TeamRows
teamList.AddRange( teams.Rows );
Re: Serialization from Xml into Object
Arjay... the reason I looked in to serialization as an option for solving my problem was due to a similar post you posted the other day on another thread ;)
No, I don't believe XmlSerializers are supported fully in Silverlight, however DataContract's are. After much messing about (especially with namespaces in the XML) I solved my problem and then refactored again and again to arrive at this fairly neat and generic solution.
Example XML:
Code:
<?xml version="1.0" encoding="utf-8"?>
<Table xmlns:S8="http://schemas.datacontract.org/2004/07/MyAppName" xmlns="S8">
<Row>
<S8:Id>1</S8:Id>
<S8:SectionId>4</S8:SectionId>
<S8:Name>Arsenal</S8:Name>
</Row>
<Row>
<S8:Id>2</S8:Id>
<S8:SectionId>2</S8:SectionId>
<S8:Name>Aston Villa</S8:Name>
</Row>
</Table>
My Team class:
Code:
[DataContract(Name="Row")]
public class Team
{
[DataMember(Order = 0)]
public Int32 Id { get; set; }
[DataMember(Order = 1)]
public Int32 SectionId { get; set; }
[DataMember(Order = 2)]
public String Name { get; set; }
}
And my new generic Table class replacing TeamTable (as I will have many more tables).
Code:
[CollectionDataContract(Namespace = "S8")]
public class Table<T> : List<T>
{
public static Table<T> Load(String tableXml)
{
using (StringReader stringReader = new StringReader(tableXml))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Table<T>), "Table", "S8");
using (XmlReader xmlReader = XmlReader.Create(stringReader))
{
return (serializer.ReadObject(xmlReader) as Table<T>);
}
}
}
}
Now all I have to do is create XML files in similar format to the above Table/Row tags and namespaces and create a supporting class similar to Team and from my main code I can do the following:
Code:
private Table<Team> _teams;
private Table<Section> _sections;
private Table<Entry> _entries;
_teams = Table<Team>.Load(teamTableXml);
_sections = Table<Section>.Load(sectionTableXml);
_entries = Table<Entry>.Load(entryXml);
Re: Serialization from Xml into Object
Quote:
Originally Posted by
rliq
Arjay... the reason I looked in to serialization as an option for solving my problem was due to a similar post you posted the other day on another thread ;)
Cool. I consider a day that I can avoid any xml document work a good day. :D
-------------------------------------------
Arjay
See my latest series on using WCF to communicate between a Windows Service and WPF task bar application.
Tray Notify - Part I Tray Notify - Part II
Need a little help with Win32 thread synchronization? Check out the following CG articles and posts:
Sharing a thread safe std::queue between threads w/progress bar updating
Simple Thread: Part I [Simple Thread: Part II
Win32 Thread Synchronization, Part I: Overview Win32 Thread Synchronization, Part 2: Helper Classes
www.iridyn.com