Problem with C# XmlSerialization - c#

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>();

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,

Deserializing xml that contains an invalid data type

I have an XML file that I need to deserialize into an object similar to this one:
public class TestObject
{
public string Name { get; set; }
public int Size { get; set; }
public TestObject()
{
Name = string.Empty;
Size = 0;
}
}
My deserialize method looks like this:
private TestObject DeserializeConfiguration(string xmlFileName)
{
XmlSerializer deserializer = new XmlSerializer(typeof(TestObject));
TextReader textReader = new StreamReader(xmlFileName);
TestObject testObj = (TestObject)deserializer.Deserialize(textReader);
textReader.Close();
return testObj;
}
This is working well enough for me but on occasion, I get an XML file that may contain an invalid data type (by "invalid", I mean with respect to the type of the object property that it should map to). For example, if my XML file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<TestObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Orion</Name>
<Size>abc</Size>
</TestObject>
Obviously I can't convert "abc" into the integer Size property of my object. When I attempt to deserialize this, I see an InvalidOperationException and, not surprisingly, the InnerException is "Input string was not in a correct format". Is it possible to catch this error, use a default value for that property of my object and continue deserializing the remainder of the XML file? If not, can anyone tell me if there's a generally regarded "best practice" for handling invalid data during deserialization?
What you would need to do is to validate the incoming XML before deserializing. Basically you want to avoid having to process badly-formed XML. After validation the deserializer can at least be sure that all incoming XML will be deserializable.
You can create an XML Schema that contains the definition of valid XML in your case, and then validate the incoming XML with the XSD (XML Schema Definition) first (see also http://www.codeguru.com/csharp/csharp/cs_data/xml/article.php/c6737/Validation-of-XML-with-XSD.htm for more details).
Good luck!

XML Deserialization with C# .NET 3.5

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.

Categories

Resources