XML Deserialization with C# .NET 3.5 - c#

I Have this XML File
<?xml version="1.0" standalone="yes"?>
<Root>
<Object>
<referenceName>People</referenceName>
<query>select * from people</query>
</Object>
<Object>
<referenceName>Countries</referenceName>
<query>select * from countries</query>
</Object>
</Root>
I need to convert into an object with C#.
I got confused how to do it.
Kindly note that I can have alot of objects in the xml file.
I know that i have to use an [XMLArray......
Thanks

The simplest trick here is at the VS command line:
xsd example.xml
xsd example.xsd /classes
Et voila; one example.cs file with example C# that shows how to get that xml from .NET objects via XmlSerializer.
In this case, I expect the following would work:
public class Root
{
[XmlElement("Object")]
public List<SomeOtherObject> Objects { get; set; }
}
public class SomeOtherObject
{
[XmlElement("referenceName")]
public string Name { get; set; }
[XmlElement("query")]
public string Query { get; set; }
}
update: validated it; yup, it works...
XmlSerializer ser = new XmlSerializer(typeof(Root));
using (XmlReader reader = XmlReader.Create(
new StringReader(xml)))
{
var obj = (Root)ser.Deserialize(reader);
// use obj
}

Use the xsd.exe tool to generate an initial set of classes to start with. Once you have those, tweak if needed (post the generated classes) and use System.Xml.Serialization.XmlSerializer to deserialize back into the runtime object.

Related

C# XmlSerializer conditionally serialialize List<T> items

i need to serialize and deserialize XML with C# XmlSerializer (or is there something better?).
[XmlElement]
public virtual List<Map> Maps { get; set; }
public class Map
{
[XmlAttribute("item")]
public string Item { get; set; }
[XmlAttribute("uri")]
public string Uri { get; set; }
}
Maps = new List<Map>{
new Map { Item="", Uri="" },
new Map { Item="something", Uri="foo" },
new Map { Item="", Uri="foo" },
}
The serializer should throw out every item with string.IsNullOrEmpty(map.Item) so that the resulting Xml only holds the map with "something".
How can I achieve this without a big hassle?:
<Maps>
<Map item="something" uri="foo" />
</Maps>
As far as I've understood, you want to filter your XML before you serialize it.
I suggest you use LINQ for this:
var filteredMaps = Maps.Where(map => !string.IsNullOrWhiteSpace(map.Item)).ToList();
Notice the .ToList() call at the end of the line. This is important, as your XmlSerializer is of type List<Map> I suppose. Put this line before you serialize your object and the result should look like this:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Map item="something" uri="foo" />
</ArrayOfMap>
Don't forget the using System.Linq;
Well you can try creating an XmlWriter that filters out all elements with an xsi:nil attribute or containing an empty string, and passes all other calls to the underlying standard XmlWriter to "clean up" serialized XML.

There is an error in XML document (2, 2).What does this mean?

I am trying to read XML document.
My XML:
<?xml version="1.0" encoding="utf-8"?>
<SplashScreen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Path>SplashScreen/Image-King</Path>
</SplashScreen>
My code which is reading XML:
XmlGameScreen = new XmlManager<GameScreen>();
XmlGameScreen.Type = currentscreen.Type;
currentscreen = XmlGameScreen.Load("LoadXML/SplashScreen.xml");
And
public Type Type;
public T Load(string path)
{
T instance;
using (TextReader textreader = new StreamReader(path))
{
XmlSerializer xml = new XmlSerializer(Type);
instance = (T)xml.Deserialize(textreader);
}
return instance;
}
I am getting error on instance = (T)xml.Deserialize(textreader); Is my XML document wrong? I am trying to read <Path>.
Update :
My Internal Exception:
Cannot serialize member 'MyRPGgame.SplashScreen._image' of type 'Microsoft.Xna.Framework.Graphics.Texture2D'
In my case it appears one of the Visual Studio 2017 version 15.5 updates caused this error when trying to open SSRS projects. The solution is to delete the *.rptproj.rsuser file from the project folder and try again.
My experience from it would be that in the 2nd line in the 2nd chararacter, there is an error.
have a look if your class names are different from the XML tags. are you maybe changing the "XML Root name" to a different one.
Have a look at the XML structure and which class are you serializing to which node.
Also, read the
MSDN Documentation about the XmlRootAttribute Class.
That usually means you have whitespace at the start of the file; check for a line-break before the <?xml.... Even better: please show the first few bytes (preferably as far as <SplashScreen) of the file as viewed in a binary editor.
It could also mean you have an invisible unicode or control character somewhere before the <SplashScreen
Just wanted to share what worked for me. I had a similar error
System.InvalidOperationException: There is an error in XML document (1, 40).
---> System.InvalidOperationException: <tsResponse xmlns='http://xxxyyyzzzz.com/api'> was not expected.
I was trying to deserialize a string to an object of type tsResponse.
After adding the following attribute [Serializable, XmlRoot(ElementName = "tsResponse", Namespace = "http://xxxyyyzzzz.com/api")] to the class tsResponse i was able to resolve my issue.
[Serializable, XmlRoot(ElementName = "tsResponse", Namespace = "http://xxxyyyzzzz.com/api")]
public class tsResponse
{
[XmlElement]
public CredentialsXml credentials { get; set; }
}
I.e had to add Namespace attribute (System.Xml.Serialization).
Try this: When you are deserializing XML to List just add an extra
line to the start i.e ArrayOfAddressDirectory as follows and don't put any space at start and end of file.
<?xml version="1.0"?>
<ArrayOfAddressDirectory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AddressDirectory>
<Owner>MS. Dhoni</Owner>
<Age>48</Age>
<Company>India</Company>
</AddressDirectory>
</ArrayOfAddressDirectory>
Here is the C# code:
namespace XmlReadProgram
{
public class AddressDirectory
{
public string Owner { get; set; }
public string Age { get; set; }
public string Company { get; set; }
}
public class Program
{
static void Main(string[] args)
{
List<AddressDirectory> adlist = new List<AddressDirectory>();
using (FileStream fileStream = File.OpenRead(#"E:\inputDirectory\address.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<AddressDirectory>));
adlist = (List<AddressDirectory>)serializer.Deserialize(fileStream);
}
//You can use foreach to print all data
Console.WriteLine(adlist[0].Owner);
Console.WriteLine(adlist[0].Age);
Console.WriteLine(adlist[0].Company);
}
}
}
In my case, a property with [XmlArrayAttribute] had the getter accessing a field with [XmlIgnoreAttribute] that was left uninitialized.
The problem in your case it's definitely the confusion between Type and template T. You are trying to construct Serializer with Type --> new XmlSerializer(Type) and then deserialize with template T ----> (T)xml.Deserialize. So the solution is to replace Type in constructing with typeof(T), and this should eliminate the initial XML document problem of (2, 2).

Deserialize XML Array Where Root is Array and Elements Dont Follow Conventions

The XML I am getting is provided by an outside source so I don't have the ability to easily reformat it. I would like to use xml attributes on my entities instead of having to write a linq query that knows how the XML and entity is formatted. Here is an example:
<?xml version="1.0"?>
<TERMS>
<TERM>
<ID>2013-2</ID>
<DESC>Spring 2013</DESC>
</TERM>
<TERM>
<ID>2013-3</ID>
<DESC>Summer 2013 Jun&Jul</DESC>
</TERM>
</TERMS>
I know the the XMLSerializer expects ArrayOfTerm instead of TERMS for example, but that I can tweak my entity to use a different element name with the xml attributes such as this:
public class TermData
{
[XmlArray("TERMS")]
[XmlArrayItem("TERM")]
public List<Term> terms;
}
public class Term
{
[XmlElement("ID")]
public string id;
[XmlElement("DESC")]
public string desc;
}
and I am deserializing the data like so:
TermData data;
XmlSerializer serializer = new XmlSerializer(typeof(TermData));
using (StringReader reader = new StringReader(xml))
{
data = (TermData)serializer.Deserialize(reader);
}
return View(data.terms);
The problem I am facing is that TERMS is the root and the array itself. If the XML were to have a root element that was not the array, I could edit my TermData class like so and it would deserialize correctly (already tested).
[XmlRoot("ROOT")]
public class TermData
{
[XmlArray("TERMS")]
[XmlArrayItem("TERM")]
public List<Term> terms;
}
Note that using TERMS as the XMLRoot does not work. Right now, my code is throwing
InvalidOperationException: There is an error in XML document (2,2).
InnerException: "<TERMS xmlns=" was not expected.
This would lead me to believe that the XML is not formatted correctly, but from my understanding the example I gave is perfectly valid XML.
This would all be trivial if I could edit the source xml, but there could be tons of other responses like this and I need to be able to flex for whatever I might get. What I'm trying to confirm is whether or not the XMLSerializer can support this type of XML structure. I've tested just about everything and can't get it deserialize without editing the XML. It would also be convenient if I didn't have to define a wrapper class (TermData) to hold the list, but this seems to only work if the xml follows the naming conventions for the serializer (ArrayOfTerm, etc).
Maybe you can try :
[XmlRoot("TERMS")]
public class TermData
{
public TermData()
{
terms = new List<Term>();
}
[XmlElement("TERM")]
public List<Term> terms{get;set;}
}
public class Term
{
[XmlElement("ID")]
public string id{get;set;}
[XmlElement("DESC")]
public string desc{get;set;}
}
Hope this will help,

Problem with C# XmlSerialization

I have xml file:
<?xml version="1.0" encoding="utf-8"?>
<LabelTypesCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance="xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<LabelTypes>
<LabelType>
<Name>LabelTypeProduct</Name>
</LabelType>
<LabelType>
<Name>LabelTypeClient</Name>
</LabelType>
</LabelTypes>
</LabelTypesCollection>
And 2 c# classes:
[Serializable]
[XmlRoot("LabelTypesCollection")]
public class LabelTypesCollection
{
private static string _labelTypesCollectionPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Path.Combine(Program.ProgramName, "LabelTypesCollection.xml"));
[XmlArray("LabelTypes", ElementName="LabelType")]
public List<LabelType> LabelTypes { get; set; }
public static LabelTypesCollection LoadAllLabelTypes()
{
FileInfo fi = new FileInfo(_labelTypesCollectionPath);
if (!fi.Exists)
{
Logger.WriteLog("Could not find size_types_collection.xml file.", new Exception("Could not find size_types_collection.xml file."));
return new LabelTypesCollection();
}
try
{
using (FileStream fs = fi.OpenRead())
{
XmlSerializer serializer = new XmlSerializer(typeof(LabelTypesCollection));
LabelTypesCollection labelTypesCollection = (LabelTypesCollection)serializer.Deserialize(fs);
return labelTypesCollection;
}
}
catch (Exception ex)
{
Logger.WriteLog("Error during loading LabelTypesCollection", ex);
return null;
}
}
}
[Serializable]
public class LabelType
{
[XmlElement("Name")]
public string Name { get; set; }
[XmlIgnore]
public string TranslatedName
{
get
{
string translated = Common.Resources.GetValue(Name);
return (translated == null) ? Name : translated;
}
}
}
And when I call:
LabelTypesCollection.LoadAllLabelTypes();
I get LabelTypeCollection object with empty LabelTypes list. There is no error or anything. Could anyone point me to the problem?
Change this
[XmlArray("LabelTypes", ElementName="LabelType")]
to this
[XmlArray]
The ElementName of an XmlArrayAttribute specifies the element name of the container, and is actually what you specify in the first parameter to the ctor! So the ctor you have says "this class serializes as a container named LabelTypes; no wait actually I want the container to be named LabelType". The named parameter is overwriting what the first unnamed parameter says.
And in fact, since you want the container element to be named LabelTypes, which is what the member is actually called, you don't need to specify it at all.
You may have been thinking of XmlArrayItemAttribute, which controls what the individual members of a serialized collection are named - but you don't need that here either.
My usual approach for working out xml serializer stuff is to build objects manually then look at the xml they serialize to. In this case, using the code you currently have produces xml like this:
<?xml version="1.0" encoding="utf-16"?>
<LabelTypesCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<LabelType>
<LabelType>
<Name>one</Name>
</LabelType>
<LabelType>
<Name>two</Name>
</LabelType>
</LabelType>
</LabelTypesCollection>
which is what tipped me off to the incorrect LabelType specifier.
Note that you also don't need the XmlRoot on LabelTypesCollection, or the XmlElement on Name, since you are just specifying what the xml serializer will come up with anyway.
Here's a suggestion.
Write a small test program that creates an instance of LabelTypesCollection, and adds some LabelType objects into it.
Then use an XmlSerializer to write the object to a file, and look at the Xml you get, to ensure that your input Xml is in the correct schema.
Maybe there's something wrong with one of your Xml elements.
I really think you get an empty list because your code can't find the xml file. Also try instantiating your list. If you have the xml path correctly.
public List<LabelType> LabelTypes = new List<LabelType>();

Why does the OnDeserialization not fire for XML Deserialization?

I have a problem which I have been bashing my head against for the better part of three hours. I am almost certain that I've missed something blindingly obvious...
I have a simple XML file:
<?xml version="1.0" encoding="utf-8"?>
<WeightStore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Records>
<Record actual="150" date="2010-05-01T00:00:00" />
<Record actual="155" date="2010-05-02T00:00:00" />
</Records>
</WeightStore>
I have a simple class structure:
[Serializable]
public class Record
{
[XmlAttribute("actual")] public double weight { get; set; }
[XmlAttribute("date")] public DateTime date { get; set; }
[XmlIgnore] public double trend { get; set; }
}
[Serializable]
[XmlRoot("WeightStore")]
public class SimpleWeightStore
{
[XmlArrayAttribute("Records")]
private List<Record> records = new List<Record>();
public List<Record> Records { get { return records; } }
[OnDeserialized()]
public void OnDeserialized_Method(StreamingContext context)
{
// This code never gets called
Console.WriteLine("OnDeserialized");
}
}
I am using these in both calling code and in the class files:
using System.Xml.Serialization;
using System.Runtime.Serialization;
I have some calling code:
SimpleWeightStore weight_store_reload = new SimpleWeightStore();
TextReader reader = new StringReader(xml);
XmlSerializer deserializer = new XmlSerializer(weight_store.GetType());
weight_store_reload = (SimpleWeightStore)deserializer.Deserialize(reader);
The problem is that I am expecting OnDeserialized_Method to get called, and it isn't.
I suspect it might have something to do with the fact that it's XML deserialization rather than Runtime deserialization, and perhaps I am using the wrong attribute name, but I can't find out what it might be.
Any ideas, folks?
There's no equivalent of OnDeserialized for XML deserialization.
See this post for workarounds: How do you find out when you've been loaded via XML Serialization?
The only way you could do that in a graceful way is to manually implement IXmlSerializable, which is not fun. Simply; XmlSerializer doesn't support serialization callbacks.
Sometimes, though, you can switch to DataContractSerializer, which still offers xml capabilities but which does support serialization callbacks. Unfortunately the xml options are limited - it won't work for you xml structure, since that uses attributes (DataContractSerializer only supports elements).
You might also look at the comments on this answer, which discusses the points from this.

Categories

Resources