Deserialize simple-plain XML to compose object - c#

I need deserialize this XML structure :
<?xml version="1.0" encoding="iso-8859-1" ?>
<vspaccess>
<vpstxid>A99C4831-D037-6A95-9DCF-E1CEC537875D</vpstxid>
<txstateid>0</txstateid>
<amount>0</amount>
<started />
<completed />
<vpsauthcode>0</vpsauthcode>
<batchid>0</batchid>
<aborted />
<released />
<applyavscv2>0</applyavscv2>
<apply3dsecure>0</apply3dsecure>
<authattempt>0</authattempt>
<threedattempt>0</threedattempt>
<eci>0</eci>
<t3mscore>0</t3mscore>
<surcharge>0</surcharge>
</vspaccess>
To a class with this structure :
[XmlRoot("vspaccess")]
public class GetTransactionDetailResponse
{
[XmlElement(Type=typeof(TransactionDetail), Order = 1)]
public TransactionDetail Detail { get; set; }
}
public class TransactionDetail
{
[XmlElement("vpstxid", Order = 1)]
public string VpsTxId { get; set; }
// Rest of properties
}
However, when I try it, the "Detail" property of the class GetTransactionDetailResponse
always is null.
I've tried combining a lot of overloads of the XmlElement attribute but the result
is always null.
I can't modify the xml structure because is returned from a web service and the structure
of the class GetTransactionDetailResponse is fixed because is used in a lot of places in the code (is legacy code).
There are a lot of samples in stackoverflow in relation to serializing/deserializing XML from/to objects, but i haven't found any that is similar to my case.

You can modify the TransactionDetail class to be like this:
[XmlRoot("vspaccess")]
public class TransactionDetail
{
public string vpstxid;
public byte txstateid;
public byte amount;
public object started;
public object completed;
public byte vpsauthcode;
public byte batchid;
public object aborted;
public object released;
public byte applyavscv2;
public byte apply3dsecure;
public byte authattempt;
public byte threedattempt;
public byte eci;
public byte t3mscore;
public byte surcharge;
}
Then you can write de-serialization code like this:
XmlSerializer serializer = new XmlSerializer(typeof(TransactionDetail));
TransactionDetail td = null;
using (StreamReader reader = new StreamReader(path))
{
td = (TransactionDetail)serializer.Deserialize(reader);
}
Finally, you can set Detail property of the GetTransactionDetailResponse object with the TransactionDetail object that you just deserialized.

Related

How to deserialize a tag nested within a text section of another tag?

How to represent the structure of the following XML for its further deserialization into classes?
<HeadElement id="1">
Text in HeadElement start
<SubElement samp="0">
Text in SubElement
</SubElement>
Continue text
</HeadElement>
My current code looks like this:
[DataContract]
public class ClaimText
{
[DataMember, XmlElement(ElementName = "claim-ref")]
public ClaimRef claimref; // { get; private set; }
public void setclaimref(ClaimRef claimref_)
{
this.claimref = claimref_;
}
[DataMember, XmlText()]
public string txt; // { get; private set; }
public void settxt(string txt_)
{
this.txt = txt_;
}
}
Given the following XML contents:
<claim id="CLM-00016" num="00016">
<claim-text>16. The midgate assembly of <claim-ref idref="CLM-00015">claim 15</claim-ref>, further comprising a second ramp member connected to an opposite side of the midgate panel for selectively covering an opposite end of the pass-through aperture. </claim-text>
</claim>
I get the object in which the link to the "claim-ref" is present, but not the entire text: only the second part of it (", further comprising ..."). How to get the whole text?
First of all you are mixing attributes for DataContractSerializer and XmlSerializer.
Ad rem: in case of mixed elements it's better to use XmlSerializer. Here is the structure that works with your XML:
[XmlRoot(ElementName = "claim")]
public class ClaimText
{
[XmlAttribute]
public string id;
[XmlAttribute]
public string num;
[XmlElement(ElementName = "claim-text")]
public ClaimInnerContents contents;
}
public class ClaimInnerContents
{
[XmlElement(ElementName = "claim-ref", Type = typeof(ClaimRef))]
[XmlText(Type = typeof(string))]
public object[] contents;
}
public class ClaimRef
{
[XmlAttribute]
public string idref;
[XmlText]
public string text;
}
ClaimRef and splitted text sections are deserialized into contents array as objects.
You can (and should) of course provide statically typed and checked accessors to particular elements of this array.

C# XML serialization preserve list<T> order

Currently I'm making a kind of History log using a List. I'm saving this list by simply serializing it with the XML serializer, however whenever I serialize the list and then deserialize it, the order is different to when I first created the list.
For example, when I first create the list, it may be in this order
A
B
C
Yet when I serialize/deserialize it may become something like
B
C
A
Is there a way or forcing the serializer to preserve the order of the list when serializing? (I've found it actually saves it in the wrong order to begin with)
Current Code:
public static List<StoredData> clipboardData = new List<StoredData>();
private void SaveClipboard()
{
XmlSerializer serializer = new XmlSerializer(typeof(List<StoredData>));
using (StreamWriter stream = new StreamWriter(historyFile))
{
serializer.Serialize(stream, clipboardData);
}
Console.WriteLine("Saved");
}
StoredData Class
[Serializable]
public class StoredData
{
public String storedClip;
public DateTime storedTime;
}
Here is a way to preserve the order when serializing your XML
[Serializable]
public class StoredData
{
[Datamember(Name = "Clip", Order = 1)]
public String storedClip;
[Datamember(Name = "Time", Order = 2)]
public DateTime storedTime;
}

What are XML element and attribute equivalents in C#?

I am trying to define C# objects based on this XML:
<UPDs LUPD="86">
<UPD ID="106">
<ER R="CREn">
<NU UID="1928456" />
<NU UID="1886294" />
<M>
<uN>bob ยท </uN>
<mO>fine :D</mO>
</M>
So far I have:
public class UDPCollection
{
List<UDP> UDPs;
public UDPCollection()
{
UDPs = new List<UDP>();
}
}
public class UDP
{
public int Id;
public List<ER> ERs;
public UDP(int id, List<ER> ers)
{
Id = id;
ERs = ers;
}
}
public class ER
{
public string LanguageR;
public ER(string languager)
{
LanguageR = languager;
}
}
My questions: What do elements map to in C#? Classes? What do attributes map to? Properties? Am I going about this the correct way?
Use the XmlSerializer class and the XmlRoot, XmlElement and XmlAttribute attributes. For example:
using System.Xml.Serialization;
...
[XmlRoot("UPDs")]
public class UDPCollection
{
// XmlSerializer cannot serialize List. Changed to array.
[XmlElement("UPD")]
public UDP[] UDPs { get; set; }
[XmlAttribute("LUPD")]
public int LUPD { get; set; }
public UDPCollection()
{
// Do nothing
}
}
[XmlRoot("UPD")]
public class UDP
{
[XmlAttribute("ID")]
public int Id { get; set; }
[XmlElement("ER")]
public ER[] ERs { get; set; }
// Need a parameterless or default constructor.
// for serialization. Other constructors are
// unaffected.
public UDP()
{
}
// Rest of class
}
[XmlRoot("ER")]
public class ER
{
[XmlAttribute("R")]
public string LanguageR { get; set; }
// Need a parameterless or default constructor.
// for serialization. Other constructors are
// unaffected.
public ER()
{
}
// Rest of class
}
The code to write out the XML is:
using System.Xml.Serialization;
...
// Output the XML to this stream
Stream stream;
// Create a test object
UDPCollection udpCollection = new UDPCollection();
udpCollection.LUPD = 86;
udpCollection.UDPs = new []
{
new UDP() { Id= 106, ERs = new [] { new ER() { LanguageR = "CREn" }}}
};
// Serialize the object
XmlSerializer xmlSerializer = new XmlSerializer(typeof(UDPCollection));
xmlSerializer.Serialize(stream, udpCollection);
Not that the XmlSerializer adds additional namepsaces but it can parse XML without them if needed. The output of the above is:
<?xml version="1.0"?>
<UPDs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" LUPD="86">
<UPD ID="106">
<ER R="CREn" />
</UPD>
</UPDs>
Use the Deserialize() method to parse it from XML into an object.
XML elements and attributes don't necessarily map to anything in particular in C#. You can make them map to classes and properties if you want, but it's not required.
That said, if you want to map your existing XML to some sort of C# data structures, the way you're doing it seems reasonable - I'd just recommend replacing your public fields with actual properties, and maybe making the list properties a less specific type - say, IEnumerable, or ICollection, or IList if they really need to be in order.

Public fields/properties of a class derived from BindingList<T> wont serialize

I'm trying to serialize a class that derives from BindingList(Floor), where Floor is a simple class that only contains a property Floor.Height
Here's a simplified version of my class
[Serializable]
[XmlRoot(ElementName = "CustomBindingList")]
public class CustomBindingList:BindingList<Floor>
{
[XmlAttribute("publicField")]
public string publicField;
private string privateField;
[XmlAttribute("PublicProperty")]
public string PublicProperty
{
get { return privateField; }
set { privateField = value; }
}
}
I'll serialize an instance of CustomBindingList using the following code.
XmlSerializer ser = new XmlSerializer(typeof(CustomBindingList));
StringWriter sw = new StringWriter();
CustomBindingList cLIst = new CustomBindingList();
Floor fl;
fl = new Floor();
fl.Height = 10;
cLIst.Add(fl);
fl = new Floor();
fl.Height = 10;
cLIst.Add(fl);
fl = new Floor();
fl.Height = 10;
cLIst.Add(fl);
ser.Serialize(sw, cLIst);
string testString = sw.ToString();
Yet testString above ends getting set to the following XML:
<CustomBindingList xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">
<Floor Height="10" />
<Floor Height="10" />
<Floor Height="10" />
</CustomBindingList>"
How do I get "publicField" or "publicProperty to serialize as well?
The short answer here is that .NET generally expects something to be a collection xor to have properties. This manifests in a couple of places:
xml serialization; properties of collections aren't serialized
data-binding; you can't data-bind to properties on collections, as it implicitly takes you to the first item instead
In the case of xml serialization, it makes sense if you consider that it might just be a SomeType[] at the client... where would the extra data go?
The common solution is to encapsulate a collection - i.e. rather than
public class MyType : List<MyItemType> // or BindingList<...>
{
public string Name {get;set;}
}
public class MyType
{
public string Name {get;set;}
public List<MyItemType> Items {get;set;} // or BindingList<...>
}
Normally I wouldn't have a set on a collection property, but XmlSerializer demands it...
XML serialization handles collections in a specific way, and never serializes the fields or properties of the collection, only the items.
You could either :
implement IXmlSerializable to generate and parse the XML yourself (but it's a lot of work)
wrap your BindingList in another class, in which you declare your custom fields (as suggested by speps)
This is known issue with XML serialization and inheriting from collections.
You can read more info on this here : http://social.msdn.microsoft.com/Forums/en-US/asmxandxml/thread/0d94c4f8-767a-4d0f-8c95-f4797cd0ab8e
You could try something like this :
[Serializable]
[XmlRoot]
public class CustomBindingList
{
[XmlAttribute]
public string publicField;
private string privateField;
[XmlAttribute]
public string PublicProperty
{
get { return privateField; }
set { privateField = value; }
}
[XmlElement]
public BindingList<Floor> Floors = new BindingList<Floor>();
}
This means you can add floors by using Floors.Add and you will get the result you want, I hope, however, I didn't try it. Keep in mind that playing around with attributes is the key to XML serialization.

IXmlSerializable

Could you guys help me I have a problem with deserialization via IXmlSerializable
var ArrayOfAccounts = new Accounts(); //This class structure I'm trying to read
Class Accounts:List<Session>{ }
Class Shedule{
public DateTime StartAt { get; set; }
public DateTime EndAt { get; set; }
}
Class Session:IXmlSerializable {
public string Name{get;set;}
public string Pass{get;set;}
public List<Shedule> Shedules = new List<Shedule>();
public void ReadXml(System.Xml.XmlReader reader){
//AND HERE IS A PROBLEM. I don't know how to implement right code here. I've tried
//code below, but this one works for the first account only, and doesn't restore others
Schedules.Clear();
XmlReader subR = reader.ReadSubtree();
if (reader.MoveToAttribute("Name"))
Name = reader.Value;
if (reader.MoveToAttribute("Password"))
Password = reader.Value;
reader.MoveToContent();
while (subR.ReadToFollowing("Schedule"))
{
XmlSerializer x = new XmlSerializer(typeof(Schedule));
object o = x.Deserialize(subR);
if (o is Schedule) Schedules.Add((Schedule)o);
}
}
And the xml itself looks like:
<Accounts>
<Session UserName="18SRO" Password="shalom99">
<Schedule>
<StartAt>0001-01-01T09:30:00</StartAt>
<EndAt>0001-01-01T16:00:00</EndAt>
</Schedule>
</Session>
</Accounts>
Since you've defined the classes, you should just be able to use XML Serialization attributes, and use the default XML deserializer.
Your structure doesn't look overly complicated, is there any particular reason you're not using serialization attributes instead of manually deserializing?
Re inherited fields... if you switch to DataContractSerializer, then fields are "opt in" rather than "opt out" - but you lose the ability to specify attributes (everything is an element). A trivial example:
[DataContract(Name="foo")]
public class Foo
{
[DataMember(Name="bar")]
public string Bar { get; set; }
public int ThisIsntSerialized {get;set;}
}
However - adding unexpected subclasses is a pain for both XmlSerializer and DataContractSerializer. Both can do it, but it isn't pretty...

Categories

Resources