Deserializing xml with multiple namespaces - c#

The data source I'm using always sends over data with the same parent class (Models in the xml), with xsi:type to determine the actual type of the class. This has been working fine until they started adding a namespace to the xsi:type. Now it won't deserialize no matter what I try.
Here's the XML:
<ModelResource xmlns:ot="http://www.example.com/otSpace">
<Models xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance xsi:type="ot:myChildClass">
Stuff here
</Models>
</ModelResource>
The root node
[XmlRoot("ModelResource")]
public class XmlRoot
{
[XmlElement("Models")]
public List<BaseObject> Bases { get; set; }
}
The parent class
[XmlInclude(typeof(MyChildClass))]
public abstract class BaseObject
{
}
The child class
[XmlType(TypeName = "myChildClass", Namespace = "http://www.example.com/otSpace")]
public class MyChildClass : BaseObject
{
}
When I deserialize this XML, I wind up with the error:
{"The specified type was not recognized: name='myChildClass', namespace='http://www.example.com/otSpace', at ."}
Thanks for your help.

These classes work with your example. I've named the classes the same as the element names just to make it easier to follow:
public class ModelResource
{
public Models Models { get; set; }
}
[XmlInclude(typeof(MyChildClass))]
[XmlRoot(Namespace = "")]
public abstract class Models
{
}
[XmlType("myChildClass", Namespace = "http://www.example.com/otSpace")]
public class MyChildClass : Models
{
[XmlText]
public string Value { get; set; }
}
See this fiddle for a working demo.

Related

serialize derived class member using XmlChoiceIdentifierAttribute

I have WSDL service class in which I would like to add extra properties. When I am trying to deserialize my derived class its giving error "You need to add XmlChoiceIdentifierAttribute to the 'ObjCreatePaperClipTransaction' member."
Here is the code I wrote on top of service classes. (executeCreatePaperClipTransaction & CreatePaperClipTransactionType are classes from proxy object)
namespace MyProject.DTO
{
[XmlType("executeCreatePaperClipTransaction")]
public partial class CustomExecuteCreatePaperClipTransaction : executeCreatePaperClipTransaction
{
[XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
[XmlElement("CreatePaperClipTransaction")]
public CustomCreatePaperClipTransactionType ObjCreatePaperClipTransaction { get; set; }
}
public partial class CustomCreatePaperClipTransactionType : CreatePaperClipTransactionType
{
[XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public executeCreateLoanIncrease ObjLoanIncreaseRequest { get; set; }
[XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 1)]
public executeCreateFreeFormEventFeePayment ObjFreeFormEventFeePaymentRequest { get; set; }
}
}
When I remove [XmlElement("CreatePaperClipTransaction")] line, its working fine. But in the seralized xml i want tag name to be CreatePaperClipTransaction and not ObjCreatePaperClipTransaction
I went through this answer but I am not sure how can i implement in my case https://stackoverflow.com/a/20379038/1169180
Rather than adding two separate [XmlElement] attributes to your ObjCreatePaperClipTransaction property, you should add one single attribute with all necessary information:
[XmlType("executeCreatePaperClipTransaction")]
public partial class CustomExecuteCreatePaperClipTransaction : executeCreatePaperClipTransaction
{
[XmlElement(ElementName = "CreatePaperClipTransaction", Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public CustomCreatePaperClipTransactionType ObjCreatePaperClipTransaction { get; set; }
}
Working .Net fiddle.
When you add multiple [XmlElement] attributes to a property, you are informing XmlSerializer that multiple different XML element names should be bound to the same property, for instance because the property value is polymorphic:
public class BaseClass
{
}
public class DerivedClass : BaseClass
{
}
public class RootObject
{
[XmlElement(ElementName = "BaseClassProperty", Type = typeof(BaseClass))]
[XmlElement(ElementName = "DerivedClassProperty", Type = typeof(DerivedClass))]
public BaseClass Property { get; set; }
}
In the example above, if the Property is assigned a DerivedClass value, the following XML will be generated:
<RootObject>
<DerivedClassProperty />
</RootObject>
That doesn't seem to apply here. You just want to bind your property to the XML element name <CreatePaperClipTransaction>.

Nest XML Elements - XML Serialization

I need to sandwich an element inside of another element. Is it possible to serialize XML like this?
http://pastebin.com/7qDE7Ses
Here is my class
[XmlRoot(ElementName = "SalesOrderMod")]
public partial class SalesOrderMod
{
[XmlElementAttribute(Order = 1)]
public string TxnID { get; set; }
[XmlElementAttribute(Order = 2)]
public string EditSequence { get; set; }
[XmlElementAttribute(Order = 3)]
public string ShipDate { get; set; }
[XmlElementAttribute(Order = 4)]
public ListRef ShipMethodRef = new ListRef();
public bool ShouldSerializeShipMethodRef()
{
return !(String.IsNullOrEmpty(ShipMethodRef.FullName));
}
[XmlElementAttribute(Order = 5)]
public string Other { get; set; }
[XmlElementAttribute(Order = 6, ElementName = "SalesOrderLineMod")]
public List<LineMod> SalesOrderLineMod = new List<LineMod>();
[XmlElementAttribute(Order = 7, ElementName = "SalesOrderLineGroupMod")]
public List<LineMod> SalesOrderLineGroupMod = new List<LineMod>();
}
You originally indicated you would like to serialize a series of elements inside an XML document like so:
<SalesOrderLineRet>
</SalesOrderLineRet>
<SalesOrderLineGroupRet>
</SalesOrderLineGroupRet>
<SalesOrderLineRet>
</SalesOrderLineRet>
You can if the types that correspond to SalesOrderLineRet and SalesOrderLineGroupRet have some common base type T, and they are stored in a List<T>. For instance, the following class definitions:
public abstract class SalesOrderLineRetBase
{
}
public class SalesOrderLineRet : SalesOrderLineRetBase
{
}
public class SalesOrderLineGroupRet : SalesOrderLineRetBase
{
}
public class RootObject
{
[XmlElement(typeof(SalesOrderLineRetBase))]
[XmlElement(typeof(SalesOrderLineRet))]
[XmlElement(typeof(SalesOrderLineGroupRet))]
public List<SalesOrderLineRetBase> SalesOrders { get; set; }
}
Will, when serialized, produce the following XML:
<RootObject>
<SalesOrderLineRet />
<SalesOrderLineGroupRet />
</RootObject>
Using [XmlElement(typeof(T))] tells XmlSerializer that the list should be serialized without an outer container element, and that items of type T can be expected to be found in the list. You must apply [XmlElement(typeof(T))] once for each type T that will be stored in the list.
(You can use List<object> if the types in the list have no other more derived base type, however I don't recommend that. I would instead recommending grouping the possible types of list entry under a specific base type.)
If you would prefer your list to be serialized with an outer container element, you can use [XmlArray] and [XmlArrayItem(typeof(T))]:
public abstract class SalesOrderLineRetBase
{
}
public class SalesOrderLineRet : SalesOrderLineRetBase
{
}
public class SalesOrderLineGroupRet : SalesOrderLineRetBase
{
}
public class RootObject
{
[XmlArray("SalesOrders")]
[XmlArrayItem(typeof(SalesOrderLineRetBase))]
[XmlArrayItem(typeof(SalesOrderLineRet))]
[XmlArrayItem(typeof(SalesOrderLineGroupRet))]
public List<SalesOrderLineRetBase> SalesOrders { get; set; }
}
Which produces the following XML:
<RootObject>
<SalesOrders>
<SalesOrderLineRet />
<SalesOrderLineGroupRet />
</SalesOrders>
</RootObject>
You must apply [XmlArrayItem(typeof(T))] for each type T that will be stored in the list.
(Since you don't include the relevant classes and XML in your question, I'm not sure which one you might want.)

XML serialization - bypass container class?

I am trying to serialize an object in a particular manner. The main class has a container class that holds some attributes, but really these attributes should be on the main class, from the point of view of the schema. Is there a way to bypass the container class and treat the properties on the container class as properties on the main class, for the purposes of serialization?
I am trying to create XML along the lines of:
<Main foo="3" bar="something">
<Others>etc</Others>
</Main>
from this code:
[System.Xml.Serialization.XmlRootAttribute("Main", Namespace = "")]
public class MainObject
{
public HelperContainer { get; set; }
public string Others { get; set; }
}
public class HelperContainer
{
[System.Xml.Serialization.XmlAttributeAttribute(AttributeName = "foo")]
public int Foo { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute(AttributeName = "bar")]
public string Bar { get; set; }
}
You may want to try implementing IXmlSerializable on MainObject to be able to control what happens when calling serialize. For the read and write xml methods specify the fields to serialize.
Check out msdn: http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
Something like:
public class MainObject : IXmlSerializable
{
public HelperContainer { get; set; }
public string Others { get; set; }
public void WriteXml (XmlWriter writer)
{
writer.WriteString(Others);
writer.WriteAttributeString("foo", HelperContainer.Foo);
writer.WriteAttributeString("bar", HelperContainer.Bar);
}
public void ReadXml (XmlReader reader)
{
Others = reader.ReadString();
//...
}
}

Single node returned after XML deserialization

I have below xml structure
<root>
<title>List</title>
<units>Total Units: 79.0</units>
<sesgrps>
<sesgrp>
<classes>
<class>
<subj_area_name>C# language</subj_area_name>
<class_name>C# Class</class_name>
</class>
<class>
<subj_area_name>VB language</subj_area_name>
<class_name>VB Class</class_name>
</class>
<class>
<subj_area_name>F# language</subj_area_name>
<class_name>F# Class</class_name>
</class>
</classes>
</sesgrp>
</sesgrps>
For that I have created classes as below:
[Serializable]
[XmlRoot("root")]
public class Data
{
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("units")]
public string Units { get; set; }
[XmlArray("sesgrps")]
[XmlArrayItem("sesgrp")]
public List<SessionGroup> SessionGroups { get; set; }
}
[Serializable]
public class SessionGroup
{
[XmlArray("classes")]
[XmlArrayItem("class")]
public List<Class> Classes { get; set; }
}
[Serializable]
public class Class
{
.....................
.....................
}
When I deserialize, I am only getting single Class item instead of 3 class Items in Classes collection.
I've just tried following code:
var file = new FileStream("Input.txt", FileMode.Open);
var serializer = new XmlSerializer(typeof(Data));
var item = (Data)serializer.Deserialize(file);
with your input XML data and following Class class declaration:
[Serializable]
public class Class
{
[XmlElement("subj_area_name")]
public string Area { get; set; }
[XmlElement("class_name")]
public string Name { get; set; }
}
And everything is fine. Result item has 1 SessionGroup instance withing SessionGroups property, which contains 3 Class objects within Classes property:
So I have to say - XmlSerializer or class declarations are not a problem here.

Overriding discriminator in Mongo

I have the following class structure:
public class Parent {
public List<Child> Children { get; set; }
}
public class Child {
}
public class MyParent : Parent {
}
public class MyChild : Child {
}
I create an instance of MyParent, and I add an instance of MyChild to Children.
When I save MyParent to Mongo, want the type to be of 'Parent', and the type of each child to 'Child'. Instead, it sets the type to MyParent and each child to MyChild, and then another program that doesn't know about MyParent and MyChild can't handle it.
I tried adding [BsonDiscriminator("Parent")] above 'MyParent', and the same with MyChild, which correctly set the '_t' value, but then I got an ambiguous class error in my own application on deserialization.
Any ideas? Thanks,
You can't have the same discriminator for two classes (that's why you were getting an error message about ambiguous discriminators).
This is a really odd situation to be in, wouldn't it be better to make your class structure match what you are doing in other languages?
In any case, you can resolve the ambiguity by using a different discriminator for the base class (which presumably will never appear in your database...).
[BsonDiscriminator("BaseParent")]
public class Parent
{
public ObjectId Id { get; set; }
public List<Child> Children { get; set; }
}
[BsonDiscriminator("BaseChild")]
public class Child
{
}
[BsonDiscriminator("Parent")]
public class MyParent : Parent
{
}
[BsonDiscriminator("Child")]
public class MyChild : Child
{
}

Categories

Resources