I have the following XML:
<Envelope>
<Body>
<RESULT>
<SUCCESS>TRUE</SUCCESS>
<RecipientId>9876543210</RecipientId>
<ORGANIZATION_ID>12345-67890-b9e6bcd68d4fb511170ab3fcff55179d</ORGANIZATION_ID>
</RESULT>
</Body>
</Envelope>
Which I'm trying to deserialize to:
[XmlRoot(ElementName = "Envelope")]
public class Add_Recipent_response
{
public string Body { get; set; }
public string RESULT { get; set; }
public string SUCCESS { get; set; }
public string RecipientId { get; set; }
public string ORGANIZATION_ID { get; set; }
}
With this method:
protected void deserializeXML(string xmlResponse)
{
XmlSerializer deserializer = new XmlSerializer(typeof(Add_Recipent_response));
using (TextReader reader = new StringReader(xmlResponse))
{
try
{
Add_Recipent_response XmlData = (Add_Recipent_response)deserializer.Deserialize(reader);
}
catch (Exception ex)
{
Console.WriteLine(ex.GetBaseException());
}
}
}
This throws an exception:
InnerException = {"Unexpected node type Element. ReadElementString
method can only be called on elements with simple or empty content.
Line 4, position 2."}
Can anyone tell me what I'm doing wrong?
Body and Result should be a classes as well because it contains elements. Something like
[XmlRoot(ElementName = "Envelope")]
public class Add_Recipent_response
{
public Body Body { get; set; }
}
public class Body
{
public Result RESULT { get; set; }
}
public class Result
{
public string SUCCESS { get; set; }
public string RecipientId { get; set; }
public string ORGANIZATION_ID { get; set; }
}
Related
There is a problem, that the object fields are initialized as null.
I've checked a couple of examples, I've set the field annotations, but seems like I did something wrong.
So here is my xml file:
<?xml version="1.0" encoding="UTF-8"?>
<getInvoiceReply>
<invoiceID value="944659502"/>
<invFastener>
<fastenerID value=""/>
<fastenerName value=""/>
<fastenerCount value=""/>
<fastenerProperty>
<propID value=""/>
<propName value=""/>
<propValue value=""/>
</fastenerProperty>
</invFastener>
</getInvoiceReply>
I've created the class hierarcy.
Root class InvoiceReply :
[XmlRoot("getInvoiceReply")]
public class InvoiceReply
{
[XmlAttribute("invoiceID")]
public string InvoiceId { get; set; }
[XmlArray("invFastener")]
public List<InvFastener> InvFastener { get; set; }
}
class InvFastener :
public class InvFastener
{
[XmlAttribute("fastenerID")]
public string FastenerID { get; set; }
[XmlAttribute("fastenerName")]
public string FastenerName { get; set; }
[XmlAttribute("fastenerCount")]
public string FastenerCount { get; set; }
[XmlArray("fastenerProperty")]
public List<FastenerProperty> FastenerProperty { get; set; }
}
class FastenerProperty:
public class FastenerProperty
{
[XmlAttribute("propID")]
public string PropId { get; set; }
[XmlAttribute("propName")]
public string PropName { get; set; }
[XmlAttribute("propValue")]
public string PropValue { get; set; }
}
Test code:
InvoiceReply i = null;
var serializer = new XmlSerializer(typeof(InvoiceReply));
using (var reader = XmlReader.Create("C:\\filePathHere\\test.xml"))
{
i = (InvoiceReply)serializer.Deserialize(reader);
}
Could anyone please suggest why is this happens?
You have a few issues with your objects. You are trying to get attributes in place of elements and your arrays are not arrays, they are merely complex elements. Below is a working example that matches your xml schema
class Program
{
static void Main(string[] args)
{
string xml = #"<?xml version=""1.0"" encoding=""UTF-8""?>
<getInvoiceReply>
<invoiceID value=""944659502""/>
<invFastener>
<fastenerID value=""""/>
<fastenerName value=""""/>
<fastenerCount value=""""/>
<fastenerProperty>
<propID value=""""/>
<propName value=""""/>
<propValue value=""""/>
</fastenerProperty>
</invFastener>
</getInvoiceReply>";
var serializer = new XmlSerializer(typeof(InvoiceReply));
var i = (InvoiceReply)serializer.Deserialize(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml)));
Console.ReadKey();
}
}
//Generic class for getting value attribute
public class ValueElement
{
[XmlAttribute("value")]
public string Value { get; set; }
}
[XmlRoot("getInvoiceReply")]
public class InvoiceReply
{
[XmlElement("invoiceID")]
public ValueElement InvoiceId { get; set; } //This is a value element
[XmlElement("invFastener")]
public List<InvFastener> InvFastener { get; set; } //This is an element, not an array
}
public class InvFastener
{
[XmlElement("fastenerID")]
public ValueElement FastenerID { get; set; }//This is a value element
[XmlElement("fastenerName")]
public ValueElement FastenerName { get; set; }//This is a value element
[XmlElement("fastenerCount")]
public ValueElement FastenerCount { get; set; }//This is a value element
[XmlElement("fastenerProperty")]
public List<FastenerProperty> FastenerProperties { get; set; } //This is an element, not an array
}
public class FastenerProperty
{
[XmlElement("propID")]
public ValueElement PropId { get; set; }//This is a value element
[XmlElement("propName")]
public ValueElement PropName { get; set; }//This is a value element
[XmlElement("propValue")]
public ValueElement PropValue { get; set; }//This is a value element
}
I'm trying to achieve a generic solution for sending and receiving XML via any means(IP, serial textfiles, etc)
All appears to work fine until i get the response String.
What i need to do is cast this response sting into the correct class type (LoginResponse, LogoffResponse, CardPaymentResponse)
etc.
I cant get a generic way to cast this XMl back into the object in an efficient manner.
Heres what i have got so far:
Sample Response Strings:
XML for LoginResponse:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ServiceResponse RequestType="Login" ApplicationSender="POSsel01" WorkstationID="1" RequestID="1254" ProtocolVersion="000000001234" DeviceType="113" SWChecksum="AC3F" CommunicationProtocol="000000000432" Model="011" ApplicatioSoftwareVersion="000000000100" Manufacturer_Id="023" OverallResult="Success" xmlns="http://www.nrf-arts.org/IXRetail/namespace" xmlns:IFSF="http://www.ifsf.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace C:\Schema\ServiceResponse.xsd"/>
XML for LogoffResponse:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<ServiceResponse RequestType="Logoff" ApplicationSender="POSsel01" WorkstationID="1" RequestID="1254" OverallResult="Success"
xmlns="http://www.nrf-arts.org/IXRetail/namespace" xmlns:IFSF="http://www.ifsf.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace C:\Schema\ServiceResponse.xsd"/>
XML for CardPaymentResponse:
<CardServiceResponse
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
RequestType="CardPayment"
ApplicationSender="1"
WorkstationID="1"
RequestID="1254"
OverallResult="LoggedOut">
<Terminal
TerminalID="1234"
TerminalBatch="1"
STAN="55" />
<Tender>
<TotalAmount
Currency="EUR">0.00</TotalAmount>
</Tender>
</CardServiceResponse>
Code for Base class to contain common fields
public abstract class IFSFResponseBase
{
[XmlAttribute()]
public string RequestType { get; set; }
[XmlAttribute()]
public string ApplicationSender { get; set; }
[XmlAttribute()]
public string WorkstationID { get; set; }
[XmlAttribute()]
public string RequestID { get; set; }
[XmlAttribute()]
public string OverallResult { get; set; }
}
ServiceResponse Type, no additional fields here
public class ServiceResponse : IFSFResponseBase
{
}
CardServiceResponse Type, Common Fields here
public class CardServiceResponse : IFSFResponseBase
{
[XmlElement("Terminal")]
public CardServiceResponseTerminal Terminal
{ get; set; }
[XmlElement("Tender")]
public CardServiceResponseTender Tender
{
get; set;
}
}
CardServiceResponse Helper Classes
public class CardServiceResponseTerminal
{
[XmlAttribute()]
public string TerminalID { get; set; }
[XmlAttribute()]
public string TerminalBatchField { get; set; }
[XmlAttribute()]
public string STANField { get; set; }
}
public class CardServiceResponseTender
{
[XmlElement("TotalAmount")]
public CardServiceResponseTenderTotalAmount TotalAmount { get; set; }
}
public class CardServiceResponseTenderTotalAmount
{
private string valueField;
[XmlAttribute()]
public string CashBackAmount
{
get;
set;
}
[XmlAttribute()]
public string Currency
{
get;
set;
}
[XmlText()]
public string Value
{
get
{
return this.valueField;
}
set
{
this.valueField = value;
}
}
}
Concrete LogoffResponse Class, no additional fields
[XmlRoot("ServiceResponse")]
public class LogoffResponse : ServiceResponse
{
}
Concrete LoginResponse Class, extra fields handled
[XmlRoot("ServiceResponse")]
public class LoginResponse : ServiceResponse
{
[XmlAttribute()]
public string POPID { get; set; }
[XmlAttribute()]
public string ReferenceNumber { get; set; }
[XmlAttribute()]
public string ProtocolVersion { get; set; }
[XmlAttribute()]
public string DeviceType { get; set; }
[XmlAttribute()]
public string SWChecksum { get; set; }
[XmlAttribute()]
public string CommunicationProtocol { get; set; }
[XmlAttribute()]
public string Model { get; set; }
[XmlAttribute()]
public string ApplicatioSoftwareVersion { get; set; }
[XmlAttribute()]
public string Manufacturer_Id { get; set; }
}
Concrete CardPaymentResponse Class, no additional fields
[XmlRoot("CardServiceResponse")]
public class CardPaymentResponse : CardServiceResponse
{
}
Concrete CardPaymentRefundResponse Class, Some extra data needed
[XmlRoot("CardServiceResponse")]
public class CardPaymentRefundResponse : CardServiceResponse
{
[XmlAttribute()]
public string ExtraValue { get; set; }
}
Helper class to remove Name space from response
public class NamespaceIgnorantXmlTextReader : XmlTextReader
{
public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader) : base(reader) { }
public override string NamespaceURI
{
get { return ""; }
}
}
With the code below, I don't know the actual response I will receive until its parsed, so I don't
know what i can use in place of the concrete class (in this case ServiceResponse).
try
{
XmlSerializer serializer = new XmlSerializer(typeof(ServiceResponse));
StringReader sr = new StringReader(XMLResponse);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
return (ServiceResponse)serializer.Deserialize(XMLWithoutNamespace);
}
catch (Exception ex)
{
//Breakpoint code here for debugging ATM, To BE REMOVED
throw;
}
That is fine for Logoff Response type, but not if it was a LoginResponse Type.
So I could Use LoginResponse but then if the response is a CardServiceResponse this will fail with an exception
since the Root element is not SERVICERESPONSE but CardServiceResponse
try
{
XmlSerializer serializer = new XmlSerializer(typeof(LoginResponse));
StringReader sr = new StringReader(XMLResponse);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
return (LoginResponse)serializer.Deserialize(XMLWithoutNamespace);
}
catch (Exception ex)
{
//Breakpoint code here for debugging ATM, To BE REMOVED
throw;
}
I tried the following hack and it will work but I'm wondering if there is a better way to achieve this
private object InternalParse(string sXML)
{
object oRetVal = null;
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(sXML);
XmlNode ReqType = xmlDoc.DocumentElement.Attributes.GetNamedItem("RequestType");
Assembly asm = Assembly.GetExecutingAssembly();
Type type = asm.GetType(asm.GetName().Name + "." + ReqType.Value + "Response");
object instance = null;
try
{
instance = (object)Activator.CreateInstance(type);
}
catch
{
//problem creating type from RequestType Name + Response appended on, the class
//probably does not exist. Lets create the parent class
type = asm.GetType(asm.GetName().Name + "." + xmlDoc.DocumentElement.Name);
instance = (object)Activator.CreateInstance(type);
}
XmlSerializer serializer = new XmlSerializer(instance.GetType());
StringReader sr = new StringReader(sXML);
NamespaceIgnorantXmlTextReader XMLWithoutNamespace = new NamespaceIgnorantXmlTextReader(sr);
oRetVal = serializer.Deserialize(XMLWithoutNamespace);
}
catch (Exception ex)
{
//Log ex here
}
return oRetVal;
}
Thanks in Advance
I have an issue with my JSON to XML code. It's not assigning the values to the Object and I cannot figure out why. Please let me know what I am doing wrong.
My C# code:
using Newtonsoft.Json;
using System.Xml;
namespace JSONTest
{
public class Program
{
static void Main(string[] args)
{
string fileName = "C:\\Code\\JSONTest\\data\\response.xml";
// Convert XML Data into JSON Data
XmlDocument xmlFile = new XmlDocument();
xmlFile.Load(fileName);
string jsonData = JsonConvert.SerializeXmlNode(xmlFile);
// Convert JSON Data into Object
RootObject root = JsonConvert.DeserializeObject<RootObject>(jsonData);
var data = root.RESPONSE_GROUP;
Console.ReadLine();
}
}
public class RootObject
{
public RESPONSEGROUP RESPONSE_GROUP { get; set; }
}
public class RESPONSEGROUP
{
public string MISMOVersionID { get; set; }
public object RESPONDING_PARTY { get; set; }
public object RESPOND_TO_PARTY { get; set; }
public RESPONSE RESPONSE { get; set; }
}
public class RESPONSE
{
public string ResponseDateTime { get; set; }
public KEY KEY { get; set; }
public STATUS STATUS { get; set; }
}
public class KEY
{
public string _Name { get; set; }
public string _Value { get; set; }
}
public class STATUS
{
public string _Code { get; set; }
public string _Condition { get; set; }
public string _Description { get; set; }
public string _Name { get; set; }
}
}
XML
<RESPONSE_GROUP MISMOVersionID="2.4">
<RESPONDING_PARTY/>
<RESPOND_TO_PARTY/>
<RESPONSE ResponseDateTime="2015-02-19T10:32:11-06:00">
<KEY _Name="LOSClientID" _Value="3000799866"/>
<STATUS _Code="S0010" _Condition="Success" _Description="TEST DESC" _Name="Complete"/>
</RESPONSE>
</RESPONSE_GROUP>
My "JSONData" string:
{"RESPONSE_GROUP":{"#MISMOVersionID":"2.4","RESPONDING_PARTY":null,"RESPOND_TO_PARTY":null,"RESPONSE":{"#ResponseDateTime":"2015-02-19T10:32:11-06:00","KEY":{"#_Name":"LOSClientID","#_Value":"3000799866"},"STATUS":{"#_Code":"S0010","#_Condition":"Success","#_Description":"THIS IS THE DESCRIPTION.","#_Name":"Complete"}}}}
The value of: root.RESPONSE_GROUP.MISMOVersionID is NULL as well as any other values that should have been populated. I know I'm doing something wrong here, but I cannot figure out what it is.
Please help! Thanks in advance.
The problem is that your JSON contains # signs in front of some property names. For example:
"#MISMOVersionID":"2.4"
There are two options here:
Fix the JSON to not have that, e.g. "#MISMOVersionID":"2.4"
Use JsonPropertyAttribute to tell Json.NET which property name to expect in the JSON, e.g.
[JsonProperty("#MISMOVersionID")]
public string MISMOVersionID { get; set; }
In my case I've a XMLTAG <phrase> that can contains one or more XMLTAG <q> but they can appear in phraseTag value in a random order.
Here it is an example of xmlcode:
<phrase level="1">
Where
<q>are</q>
<subject>you</subject>
<q>going?</q>
</phrase>
For deserialization I'm using this class:
[XmlRoot("phrase")]
public class Phrase
{
public Phrase()
{
this.Quoted = new List<string>();
}
[XmlAttribute("level")]
public int Level { get; set; }
[XmlElement("subject")]
public string Subject { get; set; }
[XmlText]
public string Value { get; set; }
[XmlElement("q")]
List<string> Quoted { get; set; }
}
My extension method is:
public static T Deserialize<T>(this XElement xElement)
{
try
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
return (T)xmlSerializer.Deserialize(xElement.CreateReader());
}
catch (Exception)
{
throw;
}
}
When I deserialize XML document all class members are successfully serialized:
Phrase.Level = 1
Phrase.Subyect = "you"
Phrase.Value = "Where"
How can I deserialize <q> tags?
I've tried to use XmlArrayAttibute and XmlArrayItemAttibute but I have not a member for this list (eg. QTags).
You need XmlElement attribute :)
[XmlRoot("phrase")]
public class Phrase
{
[XmlElement("q")]
public List<string> q { get; set; }
[XmlAttribute("level")]
public int Level { get; set; }
[XmlElement("subject")]
public string Subject { get; set; }
[XmlText]
public string Value { get; set; }
}
Given the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<userAttributeList>
<attribute>
<userId>12345678</userId>
<attId>1234</attId>
<attName>Group</attName>
<attTypeId>8</attTypeId>
<attTypeName>User Group</attTypeName>
<attData>Member</attData>
</attribute>
<attribute>
<userId>12345678</userId>
<attId>1235</attId>
<attName>Contact Name</attName>
<attTypeId>16</attTypeId>
<attTypeName>Contact Center Greeting</attTypeName>
<attData>John Smith</attData>
</attribute>
...
</userAttributeList>
I want to deserialize it into the following classes:
[Serializable]
[XmlTypeAttribute(AnonymousType = true)]
public class UserAttributeList
{
[XmlArray(ElementName = "userAttributeList")]
[XmlArrayItem(ElementName = "attribute")]
public List<UserAttribute> attributes { get; set; }
public UserAttributeList()
{
attributes = new List<UserAttribute>();
}
}
[Serializable]
public class UserAttribute
{
public String userId { get; set; }
public String attId { get; set; }
public String attName { get; set; }
public String attTypeId { get; set; }
public String attTypeName { get; set; }
public String attData { get; set; }
}
Using the code below, where GetResponseStream() returns the XML object listed above:
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "userAttributeList";
xRoot.IsNullable = true;
XmlSerializer serializer = new XmlSerializer(typeof(UserAttributeList), xRoot);
try
{
return (UserAttributeList)serializer.Deserialize(request.GetResponse().GetResponseStream());
}
catch (Exception exc)
{
return null;
}
My code compiles with no errors, but the UserAttributeList that is returned shows no child "attribute" items. No errors are thrown
I would sooner do something like:
public class userAttributeList
{
[XmlElement]
public List<UserAttribute> attribute { get; set; }
public UserAttributeList()
{
attribute = new List<UserAttribute>();
}
}
public class UserAttribute
{
public int userId { get; set; }
public int attId { get; set; }
public string attName { get; set; }
public int attTypeId { get; set; }
public string attTypeName { get; set; }
public string attData { get; set; }
}
Personally I'd use LinqToXsd. Take the existing xml, generate an xsd from it then use LinqToXsd to load that xml into a LinqToXsd object. Then you can do things like:
xml.company.com.reports.report.Load(xmlFileContents);
to build a POCO.