XML Serialisation: what happens when an object reference is added? - c#

I started with the following code:
public class ChangeRestartProcessing
{
[XmlElement("ID")]
public long TransportId { get; set; }
[XmlElement("FI")]
public Information FinalInformation { get; set; }
}
... and while serialising, everything worked fine: FI was visible in the XML serialisation result.
Now, I've made following modification:
public class ChangeRestartProcessing
{
[XmlElement("ID")]
public long TransportId { get; set; }
[XmlElement("FI")]
public Information FinalInformation { get; set; }
[XmlElement("DI")]
public Information NormalInformation { get; set; }
}
The idea is to see the FI when that object exists, and to see DI when that object exists (it never happens that both are present).
However, now I don't see any FI or DI tag in my XML serialisation result.
Is that normal and what can I do in order to make the mentioned tags visible? Do I need to create a separate class for both cases or is there another approach?

Works fine here...
using System;
using System.Xml.Serialization;
var serializer = new XmlSerializer(typeof(ChangeRestartProcessing));
serializer.Serialize(Console.Out, // has ID+FI only
new ChangeRestartProcessing
{
FinalInformation = new() { Id = 42 },
});
Console.WriteLine();
serializer.Serialize(Console.Out, // has ID+DI only
new ChangeRestartProcessing
{
NormalInformation = new() { Id = 42 },
});
public class ChangeRestartProcessing
{
[XmlElement("ID")]
public long TransportId { get; set; }
[XmlElement("FI")]
public Information FinalInformation { get; set; }
[XmlElement("DI")]
public Information NormalInformation { get; set; }
}
public class Information
{
[XmlAttribute]
public int Id { get; set; }
}
output:
<?xml version="1.0" encoding="Codepage - 850"?>
<ChangeRestartProcessing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>0</ID>
<FI Id="42" />
</ChangeRestartProcessing>
<?xml version="1.0" encoding="Codepage - 850"?>
<ChangeRestartProcessing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>0</ID>
<DI Id="42" />
</ChangeRestartProcessing>

Related

InvalidOperationException: <result xmlns=''> was not expected

I'm doing a request to server, which returns the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<result><category>...
I am using the following code to deserialize:
private ListCategories DeserializeXML()
{
XmlSerializer xml = new XmlSerializer(typeof(ListCategories));
using (FileStream fs = new FileStream("CategoriesListXML.xml", FileMode.OpenOrCreate))
{
return (ListCategories)xml.Deserialize(fs);
}
}
And i have the following for my class Categories
[Serializable]
public class ListCategories
{
public List<Categories> CategoriesList { get; set; } = new List<Categories>();
}
[Serializable]
public class Categories
{
public int id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public string image { get; set; }
public Categories() { }
public Categories(int id, int parent_id, string name, string image)
{
this.id = id;
this.parent_id = parent_id;
this.name = name;
this.image = image;
}
}
But when I deserialize the xml document I get a problem in this line:
return (ListCategories)xml.Deserialize(fs);
InvalidOperationException: <result xmlns=''> was not expected.
So can someone explain to me why the error is happening? As well as a possible solution?
Nothing in your defined model is result, so it makes sense that it is confused about what to do with <result>; the root element of ListCategories as defined is: <ListCategories>. If that isn't what you expect, you can use attributes to tell it what it should be, for example [XmlRoot("result")] on the class ListCategories. But: we'd need to see what you expect to advise on the exact attributes.
If I had to guess:
[XmlRoot("result")]
public class ListCategories
{
[XmlElement("category")]
public List<Categories> CategoriesList { get; set; } = new List<Categories>();
}
Note you can lose the [Serializable]. That has nothing to do with xml serialization. You can also probably lose the set on CategoriesList.

Game UI Xml Deserializer

the second day I'm trying to solve my problem and I think I need some help to do it. =/
So, I'm trying to do a UI for my project that for each Stage (or screen, however you name it) will take an XML and build Objects from it.
Basically, my code looks like that:
Basic class for stage's - all the other are inheriting from this one:
class BaseStage {
[XmlIgnore]
public Type Type;
[XmlIgnore]
public string XmlPath;
public BaseChildren UIScheme;
public BaseStage()
{
Type = GetType();
XmlPath = "Template/" + Type.ToString().Replace("Some.Project.Namespace.", "") + ".xml";
}
public virtual void LoadContent()
{
if (File.Exists(XmlPath))
{
using (TextReader reader = new StreamReader(XmlPath))
{
XmlSerializer uiDeserializer = new XmlSerializer(typeof(BaseChildren));
UIScheme = (BaseChildren)uiDeserializer.Deserialize(reader);
}
}
}
Some UI Classes:
public class BaseChildren
{
public List<BaseChildren> Children = new List<BaseChildren>();
public virtual void AddChild(BaseChildrenchild)
{
Children.Add(child);
}
}
public class Dialog : BaseChildren {
public string Type;
public Rectangle Position;
}
public class Label : BaseChildren {}
// ... and so on
My XML file:
<?xml version="1.0" encoding="utf-8" ?>
<UIScheme>
<Children>
<Dialog>
<Type>Blue</Type>
<Position>
<X>43</X>
<Y>100</Y>
<Width>350</Width>
<Height>200</Height>
</Position>
</Dialog>
</Children>
</UIScheme>
I've tried numerous variations and have no idea how to force serializer to load those objects =/
I also tried to override XmlSerializer and tried to write my own reading function, but it's hard to even get any tutorials how to properly do it in Google.
for fast check ,you can convert xml to C# class using this one http://xmltocsharp.azurewebsites.net/
[XmlRoot(ElementName="Position")]
public class Position {
[XmlElement(ElementName="X")]
public string X { get; set; }
[XmlElement(ElementName="Y")]
public string Y { get; set; }
[XmlElement(ElementName="Width")]
public string Width { get; set; }
[XmlElement(ElementName="Height")]
public string Height { get; set; }
}
[XmlRoot(ElementName="Dialog")]
public class Dialog {
[XmlElement(ElementName="Type")]
public string Type { get; set; }
[XmlElement(ElementName="Position")]
public Position Position { get; set; }
}
[XmlRoot(ElementName="Children")]
public class Children {
[XmlElement(ElementName="Dialog")]
public Dialog Dialog { get; set; }
}
[XmlRoot(ElementName="UIScheme")]
public class UIScheme {
[XmlElement(ElementName="Children")]
public Children Children { get; set; }
}

Empty List when deserializing XML to Object

I am having problems deserializing XML to an object with a list. The deserialize runs without error but the Resources list is empty, and I know there is one resource returned in the XML. It seems like it is just not being deserialised properly.
I am using the following code to deserialize
var ser = new XmlSerializer(typeof(SearchResult));
var test = result.Content.ReadAsStringAsync();
var t = (SearchResult)ser.Deserialize(result.Content.ReadAsStreamAsync().Result);
The variable "test" on line 2 of the code above is equal to
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ns3:searchResult total="1" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns3="ers.ise.cisco.com">
<resources>
<resource id="76a4b0f2-64e2-11e6-9f15-00505688a404" name="5555884552">
<link rel="self" href="https://servername123:9060/ers/config/guestuser/76a4b0f2-64e2-11e6-9f15-00505688a404" type="application/xml"/>
</resource>
</resources>
</ns3:searchResult>
So I would expect to get one ExistingWifiAccountDto in the Resources list. But I don't. It is empty. What am I doing wrong?
The classes for object mapping are below
[XmlRoot(ElementName = "searchResult", Namespace = "ers.ise.cisco.com")]
public class SearchResult
{
public SearchResult()
{
Resources = new List<ExistingWifiAccountDto>();
}
[XmlArray("resources")]
[XmlArrayItem("resource", typeof(ExistingWifiAccountDto))]
public List<ExistingWifiAccountDto> Resources { get; set; }
}
public class ExistingWifiAccountDto
{
public ExistingWifiAccountDto()
{
}
[XmlAttribute("id")]
public string Id { get; set; }
[XmlAttribute("name")]
public string Name { get; set; }
[XmlElement("link")]
public LinkDto Link { get; set; }
}
public class LinkDto
{
public LinkDto()
{
}
[XmlAttribute("rel")]
public string Rel { get; set; }
[XmlAttribute("href")]
public string Href { get; set; }
[XmlAttribute("type")]
public string Type { get; set; }
}
You'll have to set the namespace to an empty string for the "resources" array since it is not inherited in you situation. This should then flow down to child elements.
Try changing
[XmlArray("resources")]
to
[XmlArray("resources", Namespace = "")]
This will cause it to deserialize correctly, alternatively, you could also set each node from "resources" down with the Form attribute:
Form = XmlSchemaForm.Unqualified
Cheers

Populate custom List sub class from XML document via LINQ

I have figured out how to populate a custom class from XML data, but I ran into an issue along the way. Things were working perfectly with my existing method of populating data until I was thrown a bit of a curve ball. The new schema I was sent is similar to this:
<ITEM_REPLY>
<TRAN_ID>1320691307345</TRAN_ID>
<REPLY_CODE>0</REPLY_CODE>
<UNIT_PRICE>8.2784</UNIT_PRICE>
<SUP_LOCS>
<SUP_LOC>
<SUP_LOC_ID>001134</SUP_LOC_ID>
<COUNTRY_ID>USA</COUNTRY_ID>
<QTY_AVL>47.000</QTY_AVL>
<ITEM_UOM>EA</ITEM_UOM>
</SUP_LOC>
<SUP_LOC>
<SUP_LOC_ID>006817</SUP_LOC_ID>
<COUNTRY_ID>USA</COUNTRY_ID>
<QTY_AVL>20.000</QTY_AVL>
<ITEM_UOM>EA</ITEM_UOM>
</SUP_LOC>
</SUP_LOCS>
<MESSAGE />
<QTY_BREAKS />
</ITEM_REPLY>
Pretty standard XML schema, problem is I'm not sure how to populate my custom class with it. Here's what I do have:
static void Main(string[] args)
{
var order = ConvertXMLMessage<ItemReply>(request);
}
protected static T ConvertXMLMessage<T>(String xmlData) where T : class, new()
{
var xml = new XmlDocument();
xml.LoadXml(xmlData);
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (var xmlReader = new XmlNodeReader(xml.DocumentElement))
{
T work = (T)(serializer.Deserialize(xmlReader));
return work;
}
}
public class ItemReply
{
[XmlElement("ITEM_REPLY")]
public ItemAvlReply ITEM_REPLY { get; set; }
}
public class ItemAvlReply
{
[XmlElement("TRAN_ID")]
public string TRAN_ID { get; set; }
[XmlElement("REPLY_CODE")]
public string REPLY_CODE { get; set; }
[XmlElement("UNIT_PRICE")]
public string UNIT_PRICE { get; set; }
[XmlElement("SUP_LOCS")]
public SupplierLocations SUP_LOCS;
[XmlElement("MESSAGE")]
public string MESSAGE { get; set; }
[XmlElement("QTY_BREAKS")]
public string QTY_BREAKS { get; set; }
}
public class SupplierLocations
{
[XmlElement("SUP_LOC")]
public List<SupplierLocation> SUP_LOC;
}
public class SupplierLocation
{
[XmlElement("SUP_LOC_ID")]
public string SUP_LOC_ID { get; set; }
[XmlElement("COUNTRY_ID")]
public string COUNTRY_ID { get; set; }
[XmlElement("QTY_AVL")]
public string QTY_AVL { get; set; }
[XmlElement("ITEM_UOM")]
public string ITEM_UOM { get; set; }
}
This works perfectly minus the List<Item> part. I'm not overly experienced with LINQ and I'm not sure how to go about declaring a sub array in my class via this statement. I am also open to a different approach from creating the List<Item> part, I'm just not sure where to start otherwise. Is there a better approach for what I'm need to do? Is there an easy solution I am just unaware of in LINQ?
Here's a simple way to do it, assuming the example XML file you provided has typos. I assumed the OrderId has a closing tag, and that the closing tag for Items should be /Items.
Here's the version of the xml I used:
<Order>
<TransactionID>123</TransactionID>
<OrderID>1</OrderID>
<Items Number="2">
<Item>
<ItemName>Test</ItemName>
<Color>Red</Color>
</Item>
<Item>
<ItemName>Test1</ItemName>
<Color>Blue</Color>
</Item>
</Items>
</Order>
Here's the code to read/write the XML: (the xml variable is a String)
var order = ConvertXMLMessage<Order>(xml);
WriteXMLFile<Order>(order, #"test.xml");
Here's the ConvertXMLMessage and WriteXMLFile functions:
protected static T ConvertXMLMessage<T>(String xmlData) where T : class, new()
{
var xml = new XmlDocument();
xml.LoadXml(xmlData);
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (var xmlReader = new XmlNodeReader(xml.DocumentElement))
{
T work = (T)(serializer.Deserialize(xmlReader));
return work;
}
}
protected static void WriteXMLFile<T>(T item, String saveLocation) where T : class, new()
{
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(T));
System.IO.StreamWriter file = new System.IO.StreamWriter(saveLocation);
writer.Serialize(file, item);
file.Close();
}
and here's the class structure:
public class Order
{
[XmlElement("TransactionID")]
public string TransactionId { get; set; }
[XmlElement("OrderID")]
public string OrderId { get; set; }
[XmlElement("Items")]
public ItemsContainer Items;
}
public class ItemsContainer
{
[XmlAttribute("Number")]
public Int32 Number { get; set; }
[XmlElement("Item")]
public List<Item> Items;
}
public class Item
{
[XmlElement("ItemName")]
public string ItemName { get; set; }
[XmlElement("Color")]
public string Color { get; set; }
}
As you'll notice I added some attributes to let the XML parser know how to handle the class when it's converting from/to the XML. I also added another small class called "ItemsContainer" just to hold the details on the Items tag. If you didn't need the "Number" attribute, then you could probably find a way to do away with this. However, this should get you in the right direction.
The example I provided is a simple version of how I usually handle the situation, obviously there's some improvements you can make depending on your needs.
Edit
I changed the Item class to use ItemName instead of TransactionId. It was an oversight on my part.
Edit 2
Here's the corrections you need to make to the newly posted code. The reason the Order class worked in the previous example was it matched the root XML element. You're new XML does align with the base class. So we need to add in a couple more attributes to make this work. You can also remove your ItemReply class. It's not needed.
So here's the new classes:
[XmlRoot("ITEM_REPLY")]
public class ItemAvlReply
{
[XmlElement("TRAN_ID")]
public string TRAN_ID { get; set; }
[XmlElement("REPLY_CODE")]
public string REPLY_CODE { get; set; }
[XmlElement("UNIT_PRICE")]
public string UNIT_PRICE { get; set; }
[XmlElement("SUP_LOCS")]
public SupplierLocations SUP_LOCS;
[XmlElement("MESSAGE")]
public string MESSAGE { get; set; }
[XmlElement("QTY_BREAKS")]
public string QTY_BREAKS { get; set; }
}
public class SupplierLocations
{
[XmlElement("SUP_LOC")]
public List<SupplierLocation> SUP_LOC;
}
public class SupplierLocation
{
[XmlElement("SUP_LOC_ID")]
public string SUP_LOC_ID { get; set; }
[XmlElement("COUNTRY_ID")]
public string COUNTRY_ID { get; set; }
[XmlElement("QTY_AVL")]
public string QTY_AVL { get; set; }
[XmlElement("ITEM_UOM")]
public string ITEM_UOM { get; set; }
}
Everything else should remain the same. The parsing/converting the XML to classes should work without any changes.

Problems with Deserialization and XML

I'm using Visual Studio 2010(c#) and I am having some issues with my XML deserialization code. I can't get it to read my XML properly.
My XML reads as follows:
<?xml version="1.0" encoding="utf-8"?>
<command_strings version="1">
<commands>
<command cmd_id="1" state_id="1" label="On" cmd_type="fixed" cmd_string="1%0D" />
<command cmd_id="1" state_id="3" label="Off" cmd_type="fixed" cmd_string="0%0d" />
</commands>
</command_strings>
My code looks like:
[Serializable()]
public class Command
{
[System.Xml.Serialization.XmlAttribute("cmd_id")]
public int cmd_id { get; set; }
[System.Xml.Serialization.XmlAttribute("state_id")]
public int state_id { get; set; }
[System.Xml.Serialization.XmlAttribute("label")]
public string label { get; set; }
[System.Xml.Serialization.XmlAttribute("cmd_type")]
public string cmd_type { get; set; }
[System.Xml.Serialization.XmlAttribute("cmd_string")]
public string cmd_string { get; set; }
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("commands")]
public class CommandCollection
{
[XmlArray("commands")]
[XmlArrayItem("command", typeof(Command))]
public Command[] Command { get; set; }
}
public void XMLStrings(string myXML)
{
CommandCollection commandscollection = null;
XmlSerializer dserial = new XmlSerializer(typeof(CommandCollection));
StreamReader streamReader = new StreamReader(#"C:\123.xml");
commandscollection = (CommandCollection)dserial.Deserialize(streamReader);
streamReader.Close();
}
Any idea what I may be missing?
Any help will be greatly appreciated!
The CommandCollection class should be marked with the attribute [System.Xml.Serialization.XmlRoot("command_strings")].
You should also add a property for version and mark it with a XmlAttribute attribute.

Categories

Resources