Cant deserialize XML with type attribute - c#

I cant get the following XML deserialized because of the "type" attribute.
What I've tried so far:
The XML I want to deserialize:
<foundEntities>
<staticGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:StaticGroupType">
<number>10000</number>
<name>Gruppe A</name>
</staticGroup>
</foundEntities>
The Class:
[XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "foundEntities")]
public class FoundEntities
{
[XmlElement(ElementName = "staticGroup", Namespace = "")]
public StaticGroup staticGroup { get; set; }
}
[XmlRoot(ElementName = "staticGroup")]
[XmlInclude(typeof(StaticGroupType))]
public class StaticGroup
{
[XmlElement(ElementName = "number")]
public string number { get; set; }
[XmlElement(ElementName = "name")]
public string name { get; set; }
}
public class StaticGroupType : StaticGroup
{
}
Probably I am blind but what do I miss here? Any hint is highly appreciated.
I have generated the classes using https://xmltocsharp.azurewebsites.net/ and it gave me the following output:
[XmlRoot(ElementName = "staticGroup")]
public class FoundStaticGroup
{
[XmlElement(ElementName = "number")]
public string Number { get; set; }
[XmlElement(ElementName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
}
[XmlRoot(ElementName = "foundEntities")]
public class FoundGroupEntities
{
[XmlElement(ElementName = "staticGroup")]
public StaticGroup StaticGroup { get; set; }
}
But what I get now is an error as already had a few times before:
"The specified type was not recognized: name='StaticGroupType', namespace='http://com.f24.soap.fwi.schema', at ."

I have posted a working solution here:
DotNetFiddle Link
I'm not sure if there are external schemas but I had to remove xsi:type="ns1:StaticGroupType" to get it to work. Your XML won't parse in most readers unless there is a definition for that namespace in the XML or a schema. Not knowing what your backend service is, I can't recommend how to resolve this.
The biggest issue is you had both your classes marked with the XmlRootAtribute code attribute. Only one class can represent the root in your example. I also removed unnecessary attributes like Namespace that don't have any impact since you are using the default namespace.
Update
The issue here is with the incoming XML it is not complete, it needs a schema reference to be able to resolve the StaticGroup type. You will have to contact the people on the backend to fix this, or strip that part of the XML manually. Correct XML would be as shown below:
<foundEntities
xsi:schemaLocation="http://com.f24.soap.fwi.schema (url to back-end schema here)">
<staticGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ns1:StaticGroupType">
<number>10000</number>
<name>Gruppe A</name>
</staticGroup>
</foundEntities>

Related

XML Deserialization not working past the first element

I am attempting to use XML deserialization to convert a XML response from a host into C# objects. The root element is converted into its object and the 2nd element appears to be converted, but it's an empty element anyway. Beyond that, non of the other elements are converted. What am I missing?
I have tried many different variations of objects for each element and arrays of elements (even though an array is not needed. I even found that you can paste the XML into the editor in Visual Studio and it will create the serialized objects (edit, paste special, Paste XML As Classes), but I have not been able to get anything to work!
Here's how the XML looks:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE paymentService PUBLIC "-//MySite/DTD MySite PaymentService v1//EN" "http://dtd.mysite.com/paymentService_v1.dtd">
<paymentService version="1.4" merchantCode="ExampleCode1">
<reply>
<orderStatus orderCode="ExampleOrder1">
<reference id="YourReference">https://payments-test.mysite.com/app/hpp/integration/wpg/corporate?OrderKey=NGPPTESTMERCH1%5Ejsxml3835829684&Ticket=00146321872957902pqKhCTUf0vajKCw-X5HqZA</reference>
</orderStatus>
</reply>
</paymentService>
-OR-
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE paymentService PUBLIC "-//MySite//DTD MySite PaymentService v1//EN" "http://dtd.MySite.com/paymentService_v1.dtd">
<paymentService version="1.4" merchantCode="ExampleCode1">
<reply>
<orderStatus orderCode="ExampleOrder1">
<error code="2">
<![CDATA[Invalid address: Postal code is missing or empty.]]>
</error>
</orderStatus>
</reply>
</paymentService>
Here are the objects:
[Serializable]
[XmlRoot(ElementName = "paymentService")]
public partial class PaymentResponse
{
[XmlAttribute()]
public string version { get; set; }
[XmlAttribute()]
public string merchantCode { get; set; }
[XmlElement("reply")]
public Reply reply { get; set; }
}
[Serializable]
public partial class Reply
{
[XmlElement("orderStatus")]
public OrderStatus orderStatus {get; set; }
}
[Serializable]
public partial class OrderStatus
{
[XmlAttribute()]
public string orderCode {get; set; }
[XmlElement(ElementName = "reference",IsNullable =true)]
public Reference reference {get; set; }
[XmlElement(ElementName = "error",IsNullable =true)]
public Error error {get; set; }
}
Here's the call to do the deserialization:
XmlSerializer serializer = new XmlSerializer(typeof(PaymentResponse));
PaymentResponse response = (PaymentResponse)serializer.Deserialize(reader);
The only thing that is returned in the merchantcode and version from PaymentResponse.
You might have to tell the serializer about what to do about with the your non-primative types.
Try changing this
[XmlElement(ElementName = "reference",IsNullable =true)]
public Reference reference {get; set; }
[XmlElement(ElementName = "error",IsNullable =true)]
public Error error {get; set; }
to this
[XmlElement(ElementName = "reference", Type = typeof(Reference), IsNullable = true)]
public Reference reference {get; set; }
[XmlElement(ElementName = "error", Type = typeof(Error), IsNullable = true)]
public Error error {get; set; }
Good Luck!

Tricks for deserialize this xml element

A legacy application transmits data as xml elements.
<frame>
<reply>
<id>value_id</id>
<resultCode>value</resultCode>
<readSampleIDs>
<returnValue>
<Sample>
<SampleID> value_SampleID </SampleID>
<SamplePC> value_SamplePC </SamplePC>
<antennaName> value_antennaName </antennaName>
<channel> value_channel </channel>
<power> value_power </power>
<polarization> value_polarization </polarization>
<inventoried> value_inventoried </inventoried>
</Sample>
…
<Sample>
…
</Sample>
</returnValue>
</readSampleIDs>
</reply>
Currently the information is extracted parsing the string word by word.
I think that xml element can be deserialized into an object directly with XmlSerializer but I have some doubts on how to do it.
The element frame contains only one reply. Do I really need two different classes ?
Inside returnValue there can be zero or more Sample. In my class what is the correct type, List<Sample> or Sample[] ? Is there a real difference between the two options during deserialization ?
Most fields inside Sample are optional. How do I model this ?
When an object is serialized with XmlSerializer information about xml version and additional attributes on root element are automatically added such as:
<?xml version="1.0" encoding="utf-8"?>
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.cpandl.com">
They are not present in my example code so I'm afraid deserialization can complain about it and possibly fail.
Thanks
Filippo
If your xml contains a namespace (like in your example) then you can use these classes:
[XmlRoot(ElementName = "Sample")]
public class Sample
{
[XmlElement(ElementName = "SampleID")]
public string SampleID { get; set; }
[XmlElement(ElementName = "SamplePC")]
public string SamplePC { get; set; }
[XmlElement(ElementName = "antennaName")]
public string AntennaName { get; set; }
[XmlElement(ElementName = "channel")]
public string Channel { get; set; }
[XmlElement(ElementName = "power")]
public string Power { get; set; }
[XmlElement(ElementName = "polarization")]
public string Polarization { get; set; }
[XmlElement(ElementName = "inventoried")]
public string Inventoried { get; set; }
}
[XmlRoot(ElementName = "readSampleIDs")]
public class ReadSampleIDs
{
[XmlArray(ElementName = "returnValue")]
[XmlArrayItem(ElementName = "Sample")]
public List<Sample> Sample { get; set; }
}
[XmlRoot(ElementName = "reply", Namespace = "http://www.cpandl.com")]
public class Reply
{
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "resultCode")]
public string ResultCode { get; set; }
[XmlElement(ElementName = "readSampleIDs")]
public ReadSampleIDs ReadSampleIDs { get; set; }
}
If you are only interested in node reply and this is the only one. You can deserialize only this node:
XNamespace loNameSpace = "http://www.cpandl.com";
XDocument loDoc = XDocument.Parse(Properties.Settings.Default.TransmitsData);
var loReplyElement = loDoc.Element(loNameSpace.GetName("PurchaseOrder"))
.Element(loNameSpace.GetName("frame"))
.Element(loNameSpace.GetName("reply"));
using (var loReader = loReplyElement.CreateReader())
{
var loSerializer = new XmlSerializer(typeof(Reply));
var loReply = (Reply)loSerializer.Deserialize(loReader);
Console.WriteLine(loReply.Id);
}

List Property Not Being Populated on Deserialisation from XML

I am trying to deserialise an xml file to c# classes. I used an online tool to generate the classes for me as the structure of the XML file is quite complex. This worked well except for the population of repeated items into a List property in the main class.
I am using DotNet 4.5, C# in WPF.
A simplified version of the xml file is as follows:
<orderMessage xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:gs1:ecom:order:xsd:3">
<order xmlns="">
<creationDateTime>2017-07-10T00:00:00</creationDateTime>
<documentStatusCode>ORIGINAL</documentStatusCode>
<documentActionCode>ADD</documentActionCode>
</order>
<order xmlns="">
<creationDateTime>2017-07-10T00:00:00</creationDateTime>
<documentStatusCode>ORIGINAL</documentStatusCode>
<documentActionCode>ADD</documentActionCode>
</order>
</orderMessage>
The classes that I am using are as below:
[XmlRoot(ElementName = "order")]
public class Order
{
[XmlElement(ElementName = "creationDateTime")]
public string CreationDateTime { get; set; }
[XmlElement(ElementName = "documentStatusCode")]
public string DocumentStatusCode { get; set; }
[XmlElement(ElementName = "documentActionCode")]
public string DocumentActionCode { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
}
[XmlRoot(ElementName = "orderMessage", Namespace = "urn:gs1:ecom:order:xsd:3")]
public class OrderMessage
{
[XmlElement(ElementName = "order")]
public List<Order> Order { get; set; }
[XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsd { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
}
The deserialization code is as follows:
XmlSerializer serializer = new XmlSerializer(typeof(OrderMessage));
StreamReader reader = new StreamReader(filename);
OrderMessage newOrderMessage;
try
{
newOrderMessage = (OrderMessage)serializer.Deserialize(reader);
}
catch (Exception e)
{
throw e;
}
reader.Close();
When I run the code it runs without error but I end up with an empty list. There were other structures in the xml (that were not repeated structures - therefore no list property) that populated without problem that I have omitted.
I have looked at a number of questions similar to mine but they seem to suggest the same method I am using.
I am unable to change the XML as it is from a third party.
I would greatly appreciate it if anyone could point me in the right direction.
BTW - I know that catching an error and then throwing it is of no use whatsoever but I just did that to add a breakpoint so I could look at the inner exceptions if there were any. I will make the error handling more meaningful once I have the process working.
The issue is your Order property - the namespace will be inherited from OrderMessage, so it is urn:gs1:ecom:order:xsd:3 when it should be empty. You must specify this explicitly.
You can also remove a bunch of the namespace related attributes from your model. This is all you need:
[XmlRoot("orderMessage", Namespace = "urn:gs1:ecom:order:xsd:3")]
public class OrderMessage
{
[XmlElement("order", Namespace = "")]
public List<Order> Orders { get; set; }
}
public class Order
{
[XmlElement("creationDateTime")]
public string CreationDateTime { get; set; }
[XmlElement("documentStatusCode")]
public string DocumentStatusCode { get; set; }
[XmlElement("documentActionCode")]
public string DocumentActionCode { get; set; }
}
As an aside, throw e; in your deserialisation code is probably not what you want to do (see this question). Given you're not actually handling the exception, you can remove the try / catch entirely in this case.
You should also enclose your StreamReader in a using block to ensure it is disposed after use.

Deserialize xml Elements with same Attributes

I am deserializing a xml file with an attribute and a xml text. The problem is that those elements have the same attributes. So I am always getting the error that I must not have two identical TypeNames in XmlType.
My xml:
<group_id xsi:type="xsd:int">1</group_id>
<name xsi:type="xsd:int">myNameView</name>
And my C#:
[XmlType(AnonymousType = true, Namespace = "http://www.w3.org/2001/XMLSchema", TypeName = "int")]
[XmlRoot(ElementName = "group_id")]
public class Group_id
{
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
[XmlText]
public string Text { get; set; }
}
[XmlType(AnonymousType = true, Namespace = "http://www.w3.org/2001/XMLSchema", TypeName = "int")]
[XmlRoot(ElementName = "name")]
public class Name
{
[XmlAttribute(AttributeName = "type", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string Type { get; set; }
[XmlText]
public string Text { get; set; }
}
The problem is the TypeName in XmlType Attribute. If I name only one element with a TypeName it is correctly deserialized.
XmlSerializer handles types for you, based on the xsi:type attribute. By trying to handle these yourself, you're causing it some grief.
If you declare your elements as object, then the serializer will use the type attributes to determine how to deserialize the values. Note as your example is just a fragment, I've assumed root element called root:
[XmlRoot("root")]
public class Root
{
[XmlElement("group_id")]
public object GroupId { get; set; }
[XmlElement("name")]
public object Name { get; set; }
}
Now when you deserialize your example, you'd actually get an exception (as myNameView isn't an integer). You can fix by either changing the type to xsd:string or changing the value to a valid integer.
In the event the XML was valid, you'd see that the types deserialized map directly to the type attributes. See this fiddle for a working demo.

How to add xsi:schemaLocation to serialized object

How can I add the following xsi:schemaLocation to a serialized class?
<ern:NewReleaseMessage xmlns:ern="http://ddex.net/xml/2010/ern-main/32"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
LanguageAndScriptCode="en"
xsi:schemaLocation="http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd"
MessageSchemaVersionId="2010/ern-main/32">
Here is what I have done so far:
public class NewReleaseMessage
{
[XmlAttribute]
public string LanguageAndScriptCode { get; set; }
[XmlAttribute("schemaLocation", Namespace = "http://ddex.net/xml/2010/ern-main/32")]
public string schemaLocation = "http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd";
[XmlAttribute]
public string MessageSchemaVersionId { get; set; }
[XmlElement()]
public MessageHeader MessageHeader { get; set; }
}
When I deserialize the xml to the object in VS I get:
{"The method or operation is not implemented."
There is an error in XML document (5, 44) - This actually points to the line: xsi:schemaLocation="http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd"
Soultion:
[XmlAttribute(AttributeName = "schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string schemaLocation { get; set; }
Below is what worked for me:
Note : "XmlAttributeAttribute"
[XmlAttributeAttribute(AttributeName = "schemaLocation", Namespace = "http://ddex.net/xml/2010/ern-main/32")]
public string schemaLocation = "http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd";

Categories

Resources