Deserializing XML to class, some elements not not pulling through - c#

I am having some difficulties figuring out how to correctly structure my classes to mirror the XML that I am attempting to deserialize. Most elements are coming through, but for example, in the XML below the UOMs object is not being deserialized.
Example XML:
<Items xmlns="http://www.manh.com/ILSNET/Interface" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Item>
<Desc>Desc Field Example Value</Desc>
<Item>PE0000009790</Item>
<ItemCategories>
<Action>SAVE</Action>
<Category1>COMPONENT</Category1>
<Category2>Category2ExampleValue</Category2>
</ItemCategories>
<ItemClass>
<Action>SAVE</Action>
<ItemClass>Example ItemClass</ItemClass>
</ItemClass>
<UOMS>
<UOM>
<Action>SAVE</Action>
<ConvQty>1</ConvQty>
<DimensionUm>IN</DimensionUm>
<Height>0.0</Height>
<Length>0.0</Length>
<QtyUm>EA</QtyUm>
<Sequence>1</Sequence>
<Weight>0</Weight>
<WeightUm>LB</WeightUm>
<Width>0.0</Width>
</UOM>
</UOMS>
</Item>
</Items>
I am using basic XML deserialization code, which works well but just providing for background:
using (FileStream fileStream = new FileStream(Filename, FileMode.Open))
{
this.CreatedObjects = (ItemList)serializer.Deserialize(fileStream);
}
The first class is below:
[XmlRoot(ElementName = "Items", Namespace = "http://www.manh.com/ILSNET/Interface")]
public class ItemList
{
[XmlElement("Item")]
public Item[] Items { get; set; }
}
public class Item
{
[XmlElement("ItemCategories")]
public ItemCategory[] Categories { get; set; }
[XmlElement("ItemClass")]
public ItemClass[] Classes { get; set; }
[XmlElement("UOMS")]
public ItemUOMS UOMs { get; set; }
[XmlElement("Desc")]
public string Description { get; set; }
[XmlElement("Item")]
public string Id { get; set; }
}
The second class, which I am struggling to populate, is below (this class is a member of the Item class shown above:
[XmlRoot(ElementName = "UOMS", Namespace = "http://www.manh.com/ILSNET/Interface")]
public class ItemUOMS
{
[XmlElement("UOM")]
public ItemUOM[] UOM { get; set; }
}
[XmlRoot(ElementName = "UOM", Namespace = "http://www.manh.com/ILSNET/Interface")]
public class ItemUOM
{
[XmlElement("Action")]
public string Action { get; }
[XmlElement("DimensionUm")]
public string DimensionUnit { get; }
[XmlElement]
public decimal Height { get; }
[XmlElement]
public decimal Length { get; }
[XmlElement("QtyUm")]
public string QtyUnit { get; }
[XmlElement("ConvQty")]
public decimal Quantity { get; }
[XmlElement]
public int Sequence { get; }
[XmlElement]
public decimal Weight { get; }
[XmlElement("WeightUm")]
public string WeightUnit { get; }
[XmlElement]
public decimal Width { get; }
}
Unfortunately, I don't get an error, but instead the UOMs objects are just default objects without any values being set. I tried to reference some XML to C# Class tools online that are supposed to output C# classes for you based on XML provided to the tool, but their classes didn't seem to solve the issue for me either. I attempted to use [XmlArray] / [XmlArrayItem], but neither had any effect either.
If you need any more information from me, please let me know. Thanks for any assistance/guidance you are able to provide in advance.

Related

How to parse XML with several Attributes and an options list

I have an XML file that looks something similar to this:
<root>
<data label="product data" min="0" max="10">
<option>
<id>1</id>
<name>Name1</name>
</option>
<option>
<id>2</id>
<name>Name2</name>
</option>
<option>
<id>3</id>
<name>Name3</name>
</option>
</data>
</root>
I need to retreive both data attributes and the option list.
I tried this:
[XmlRoot(ElementName = "root")]
public class Data
{
// Retreive data attributes
[XmlElement(ElementName = "data")]
public Options Attributes { get; set; }
// Retrieve option list
[XmlArray("data")]
[XmlArrayItem("option", Type = typeof(GeneralOptions))]
public GeneralOptions[] Options { get; set; }
}
Optional classes:
Options
public class Options
{
[XmlAttribute("label")]
public string Label{ get; set; }
[XmlAttribute("min")]
public string Min{ get; set; }
[XmlAttribute("max")]
public string Max{ get; set; }
}
GeneralOptions
public class GeneralOptions
{
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "name")]
public string Name{ get; set; }
}
But when I try to deserialize the object, it launches the following exception:
The XML element 'data' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.
I imagine the problem is that I'm trying to retreive the same element "twice". But I need to retreive both things. I cannot use the [Attribute] thing because there are several Attributes to retreive, and I need to do this with several XML Elements with the same format and I want to reuse it.
So, how can I retreive both of them?
You'll need to restructure it slightly:
[XmlRoot("root")]
public class Data
{
[XmlElement("data")]
public OptionsData Options { get; set; }
}
public class OptionsData
{
[XmlAttribute("label")]
public string Label { get; set; }
[XmlAttribute("min")]
public string Min { get; set; }
[XmlAttribute("max")]
public string Max { get; set; }
[XmlElement("option")]
public List<GeneralOptions> Items { get; } = new List<GeneralOptions>();
}
public class GeneralOptions
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("name")]
public string Name { get; set; }
}
I suggest using xmltocsharp or anyother tools to convert the XML to C# Models within seconds... (eliminates all manual mistakes)
As mentioned by #canton7, another easy method is using Visual Studio: Edit -> Paste Special -> Paste XML As Classes
[XmlRoot(ElementName="option")]
public class Option {
[XmlElement(ElementName="id")]
public string Id { get; set; }
[XmlElement(ElementName="name")]
public string Name { get; set; }
}
[XmlRoot(ElementName="data")]
public class Data {
[XmlElement(ElementName="option")]
public List<Option> Option { get; set; }
[XmlAttribute(AttributeName="label")]
public string Label { get; set; }
[XmlAttribute(AttributeName="min")]
public string Min { get; set; }
[XmlAttribute(AttributeName="max")]
public string Max { get; set; }
}
[XmlRoot(ElementName="root")]
public class Root {
[XmlElement(ElementName="data")]
public Data Data { get; set; }
}

Deserialize XML list of elements of string element each

I'm not able to deserialize the following secition of an XML with C#
<mainfile>
<portfolio>
<fotos>
<foto> <!CDATA[https://whatever.com/fotos/E/400/photo.JPG]]>
</foto>
</fotos>
</portfolio>
<portfolio>
<fotos>
<foto> <!CDATA[https://whatever.com/fotos/E/400/photo1.JPG]]>
</foto>
</fotos>
</portfolio>
</mainfile>
I think it should be quite straight forward, but when deserializing it always returns an empty list. Here is the code:
[XmlRoot("mainfile")]
public class MainFile
{
public MainFile()
{
porftolios= new List<Portfolio>();
}
[XmlElement("portfolio")]
public List<Portfolio> Portfolios{ get; set; }
}
public class Portfolio
{
....
[XmlElement("fotos")]
public List<Foto> Fotos { get; set; }
}
public class Foto
{
[XmlText]
public string data{ get; set; }
}
Thanks.
EDIT.
From HimBromBeere's solution i've chaged the following code, with a successful result:
public class Portfolio
{
....
[XmlArray("fotos")]
[XmlArrayItem("foto")]
public List<Foto> Fotos { get; set; }
}
public class Foto
{
[XmlText]
public string data{ get; set; }
}
When using XmlElement for list-types the container-list-element within the resulting xml is lost. As you do have that container for your fotos-tag, you should use XmlArrayItem for it:
public class Portfolio
{
[XmlArray("fotos")]
[XmlArrayItem("foto")]
public List<Foto> Fotos { get; set; }
}
If you can change the xml however I would suggest to use a consistent style for your collections, either use the container for your portfolio also, or omit it for your fotos.

C# Xml deserialization Element in object property

I'm consuming a Web API, and i get an xml result:
<tarification cle="XXXX">
<gamme reference="refX">
<tarif formula="F100">44.84</tarif>
<tarif formula="F125">47.63</tarif>
<tarif formula="F150">57.34</tarif>
<tarif formula="F200">67.95</tarif>
<option name="indiv-acc">0.5</option>
<option name="rap-cor">6.06</option>
</gamme>
</tarification>
I use this model to deserialize :
[XmlRoot(ElementName = "tarification", Namespace="")]
public class TarifResponse
{
[XmlElement(ElementName = "gamme")]
public Gamme Gamme { get; set; }
}
public class Gamme
{
[XmlAttribute(AttributeName="reference")]
public string Name { get; set; }
[XmlElement(ElementName = "tarif")]
public Formula[] Formulas { get; set; }
[XmlElement(ElementName = "option")]
public Option[] Options { get; set; }
}
public class Formula
{
[XmlAttribute(AttributeName="formula")]
public string Name { get; set; }
// WRONG ATTRIBUTE.. but witch one ?
[XmlElement]
public Decimal Amount { get; set; }
}
public class Option
{
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
// WRONG ATTRIBUTE.. but witch one ?
[XmlElement]
public Decimal Amount { get; set; }
}
The TarifResponse object is created, all fields are filled, except the two amounts fields. I expect this is because the right xml should be:
<amount>5.5</amount>
inside tarif or option elements..
Is this format is deserializable ?
Is there a way to this with attribute ?
Is this even an acceptable xml format ?
thank you
The [XmlText] attribute will get the inner text of the node. You might need to use [XmlText(Type=typeof(decimal))] to get the number parsed.
public class Option
{
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlText]
public Decimal Amount { get; set; }
}

Unable to Deserialize XML

I have the following code but unable to deserialize, can you see where I'm going wrong? It only catch the first record on the first array item.
[XmlRootAttribute("Booking")]
public class Reservation
{
[XmlArray("Included")]
[XmlArrayItem("Meals")]
public Meals[] Food { get; set; }
[XmlArrayItem("Drinks")]
public Drinks[] Drink { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Here's the associated XML
<?xml version="1.0" standalone="yes"?>
<Booking>
<Included>
<Meals
Breakfast="True"
Lunch="True"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="False"
Wine="False">
</Drinks>
</Included>
<Included>
<Meals
Breakfast="True"
Lunch="False"
Dinner="False">
</Meals>
<Drinks
Soft="True"
Beer="True"
Wine="True">
</Drinks>
</Included>
</Booking>
I'm a bit of a newbie so any help would be great, unfortunately after trawling through the many exmaples you already have online I still haven't been able to figure this out.
Use the following example and apply this syntax in ListItem array,
[XmlType("device_list")]
[Serializable]
public class DeviceList {
[XmlAttribute]
public string type { get; set; }
[XmlElement( "item" )]
public ListItem[] items { get; set; }
}
following link contains all the syntax & attributes
http://msdn.microsoft.com/en-us/library/2baksw0z.aspx
I see no obvious way your class structure could be matched to the XML document. The underlying organizations seem to be quite different.
The following class hierarchy could be easily deserialized from the XML document you provide (assuming your document covers the general case) :
[Serializable]
[XmlRoot("Booking")]
public class Booking : List<Included>
{
}
[Serializable]
public class Included
{
public Meals Meals { get; set; }
public Drinks Drinks { get; set; }
}
public class Meals
{
[XmlAttribute("Breakfast")]
public string Breakfast { get; set; }
[XmlAttribute("Lunch")]
public string Lunch { get; set; }
[XmlAttribute("Dinner")]
public string Dinner { get; set; }
}
public class Drinks
{
[XmlAttribute("Soft")]
public string Softs { get; set; }
[XmlAttribute("Beer")]
public string Beer { get; set; }
[XmlAttribute("Wine")]
public string Wine { get; set; }
}
Then, deserialization code would be : (serializedObject is the string containing your serialized object)
XmlSerializer ser = new XmlSerializer(typeof (string));
XmlReader reader = XmlTextReader.Create(new StringReader(serializedObject));
var myBooking = ser.Deserialize(reader) as Booking;

Complex XML deserialization in c#

Here's my blob:
<Attributes>
<SomeStuff>...</SomeStuff>
<Dimensions>
<Weight units="lbs">123</Weight>
<Height units="in">123</Height>
<Width units="in">123</Width>
<Length units="in">123</Length>
</Dimensions>
</Attributes>
I'm trying to deserialize it using xml attributes on my class members, but I'm having trouble. I'm trying to use a "Dimensions" type with a unit and value. How do I get the unit as an attribute and get the value to the value?
Here's what I'm trying:
[Serializable]
public class Attributes
{
public object SomeStuff { get; set; } // Not really...
public Dimensions Dimensions { get; set; }
}
[Serializable]
public class Dimensions
{
public Dimension Height { get; set; }
public Dimension Weight { get; set; }
public Dimension Length { get; set; }
public Dimension Width { get; set; }
}
[Serializable]
public class Dimension
{
[XmlAttribute("units")]
public string Units { get; set; }
[XmlElement]
public decimal Value { get; set; }
}
I know that this code is expecting an actual "Value" element inside the dimension. But I can't find any attribute decorators in the .NET library that could tell it to use the actual text of the element for this, other than XmlText, but I want a decimal... Is a proxy field the only option? (e.g.
[XmlText] public string Text { get; set; }
[XmlIgnore]
public decimal Value
{
get { return Decimal.Parse(this.Text); }
set { this.Text = value.ToString("f2"); }
}
Thanks.
You can use XmlAttribute for the attribute, and XmlText for the text. So try changing your public decimal Value to be decorated with [XmlText].
[Serializable]
public class Dimension
{
[XmlAttribute("units")]
public string Units { get; set; }
[XmlText]
public decimal Value { get; set; }
}

Categories

Resources