XmlSerializer Deserializing List Without namespace - c#

Trying to deserialize List.
Im getting the following error:
System.InvalidOperationException: There is an error in XML document
(1, 2). ---> System.InvalidOperationException: was not expected.
Saw other quesitons like : {"<user xmlns=''> was not expected.} Deserializing Twitter XML but this does not solve my problem either.
This is an Xml Sample
<authorizations>
<id>111</id>
<name>Name 1</name>
<Lists>
<List>
<id>1</id>
<id>2</id>
</List>
</Lists>
</authorizations>
<authorizations>
<id>222</id>
<name>Name 2</name>
<List />
</authorizations>
<authorizations>
<id>333</id>
<name>Name 3</name>
<List />
</authorizations>
The class are created as follow:
public class Authorization
{
[XmlElement("id")]
public string Id{ get; set; }
[XmlElement("name")]
public string Name{ get; set; }
[XmlArray("Lists")]
[XmlArrayItem("List")]
public List[] Items{ get; set; }
}
public class List
{
[XmlElement("id")]
public string Id{ get; set; }
}
public class AuthorizationList
{
[XmlArray("authorizations")]
public Authorization Authorizations{ get; set; }
}
Have tried changing the list to XmlArray, XmlArrayItem or Element. but still get the same error when I deserialize.
Deserializing Code Sample:
public static T FromXml<T>(string xmlString)
{
T obj = default(T);
if (!string.IsNullOrWhiteSpace(xmlString))
{
using (var stringReader = new StringReader(xmlString))
{
var xmlSerializer = new XmlSerializer(typeof(T));
obj = (T)xmlSerializer.Deserialize(stringReader);
}
}
return obj;
}

This is ALL premised on the assumption that you have minimal control over the xml and don't have the luxury of changing that too much. As others have noted, it is not well-formed. Here is one way to get serialization to work with minimal changes to your XML and types. First, get rid of your AuthorizationList type and assign an XmlType attribute to your Authorization type (this step serves to simply pluralize the name to match how your XML has it).
[XmlType("authorizations")]
public class Authorization { ... }
public class List { ... }
Wrap your XML in the following root element:
<ArrayOfAuthorizations>
...
</ArrayOfAuthorizations>
The XML now represents a list of "authorizations" so to deserialize is just this:
List<Authorization> l = FromXml<List<Authorization>>(xml);
Another Solution:
Change the Authorizations member to be of type Authorization[] (array type rather than singular) and to have an XmlElement attribute (not XmlArray). Apply the XmlType attribute to the Authorization (as with the above solution this is to match the xml since it has the pluralized name for each array element).
[XmlType("authorizations")]
public class Authorization
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("name")]
public string Name { get; set; }
[XmlArray("Lists")]
[XmlArrayItem("List")]
public List[] Items { get; set; }
}
public class List
{
[XmlElement("id")]
public string Id { get; set; }
}
public class AuthorizationList
{
[XmlElement("authorizations")]
public Authorization[] Authorizations { get; set; }
}
Like before, you need to wrap your XML with the matching 'AuthorizationList' root element:
<AuthorizationList>
...
</AuthorizationList>
Then you deserialize instance of your AuthorizationList type rather that List<T> as with the previous solution.
AuthorizationList l = FromXml<AuthorizationList>(xml);
Note that the root XML element will also need to match that type name also.
<AuthorizationList>
<authorizations>
<id>111</id>
<name>Name 1</name>
<Lists>
<List>
<id>1</id>
<id>2</id>
</List>
</Lists>
</authorizations>
<authorizations>
<id>222</id>
<name>Name 2</name>
<List />
</authorizations>
<authorizations>
<id>333</id>
<name>Name 3</name>
<List />
</authorizations>
</AuthorizationList>

Related

Cannot deserialize sub-elements to list of objects

I am having problems serializing elements of an XML to a list of objects.
This is the XML:
<result>
<stats>
<numitemsfound>1451</numitemsfound>
<startfrom>0</startfrom>
</stats>
<items>
<item>
<id>1</id>
<markedfordeletion>0</markedfordeletion>
<thumbsrc>
</thumbsrc>
<thumbsrclarge>
</thumbsrclarge>
...
<datasource>65</datasource>
<data>
<amount>100</amount>
<kj>389</kj>
<kcal>92.91</kcal>
<fat_gram>0.2</fat_gram>
<fat_sat_gram>-1</fat_sat_gram>
<kh_gram>20.03</kh_gram>
</data>
<servings>
<serving>
<serving_id>386</serving_id>
<weight_gram>150</weight_gram>
</serving>
</servings>
</item>
</result>
The classes I prepared for serialization are
[XmlType("item")]
public class Item
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlAttribute("markedfordeletion")]
public string markedfordeletion { get; set; }
...
[XmlAttribute("datasource")]
public string datasource { get; set; }
[XmlElement("data")]
public Data data { get; set; }
[XmlElement("servings")]
public List<Serving> servings { get; set; }
}
}
This is how I try to serialize the xml
public void ParseSearch(string xml)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Item>), new XmlRootAttribute("item"));
StringReader stringReader = new StringReader(xml);
var productList = (List<Item>)serializer.Deserialize(stringReader);
}
But I get the error ----> System.InvalidOperationException : <result xmlns=''> was not expected. Can you please help me solve this problem?
You have to use a serializer which serializes an instance of result, not of type List:
XmlSerializer serializer = new XmlSerializer(typeof(Result), new XmlRootAttribute("result")); //whatever `Result` actually is as type).
You canĀ“t serialize and de-serialize just parts of a document, either the whole one or nothing at all.
So you need a root-type:
[XmlRoot("result")]
public class Result
{
public Stats Stats {get; set;}
[XmlArray("items")]
[XmlArrayItem("item")]
public List<Item> Items { get; set; }
}

Deserializing an XML document with the root being a list

I have an XML document provided to me externally that I need to import into my application. The document is badly written, but not something I can really do much about.
<?xml version="1.0" encoding="iso-8859-1"?>
<xml>
<Items>
<Property1 />
<Property2 />
...
</Items>
<Items>
<Property1 />
<Property2 />
...
</Items>
...
</xml>
How should I go about using the XmlSerializer for this?
It doesn't seem to matter what class setup I use, or wether I put XmlRoot(ElementName="xml") on my base class it always says that the <xml xmlns=''> is unexpected.
Edit: Added the C# code I am using
[XmlRoot(ElementName = "xml")]
public class Container
{
public List<Items> Items { get; set; }
}
public class Items
{
public short S1 { get; set; }
public short S2 { get; set; }
public short S3 { get; set; }
public short S4 { get; set; }
public short S5 { get; set; }
public short S6 { get; set; }
public short S7 { get; set; }
}
public class XMLImport
{
public Container Data{ get; private set; }
public static XMLImport DeSerializeFromFile(string fileName)
{
XMLImport import = new XMLImport();
XmlSerializer serializer = new XmlSerializer(typeof(Container));
using (StreamReader reader = new StreamReader(fileName))
import.Data = (Container)serializer.Deserialize(reader);
return import;
}
}
Say you have a class Items maps to each <Items> node:
public class Items
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
You can deserialize your list of Items like this:
var doc = XDocument.Parse(
#"<?xml version=""1.0"" encoding=""iso-8859-1""?>
<xml>
<Items>
<Property1 />
<Property2 />
</Items>
<Items>
<Property1 />
<Property2 />
</Items>
</xml>");
var serializer = new XmlSerializer(typeof(List<Items>), new XmlRootAttribute("xml"));
List<Items> list = (List<Items>)serializer.Deserialize(doc.CreateReader());
The root of your XML is not a List, the root of your xml is the <xml> node I think you are just confused by its name :)
please visit the following link, It has many good answers voted by many people.
Here is the link: How to Deserialize XML document
Error Deserializing Xml to Object - xmlns='' was not expected
Simply take off the Namespace =:
[XmlRoot("xml"), XmlType("xml")]
public class RegisterAccountResponse {...}

xml Serialization and Deserialization (hide one node header)

I have an XML file and I need to deserialize it. Without bypassing all the nodes, just deserilizing the XML file to an object.
Is it possible to hide from the result ActionGetSiteResultData or only one way
use custom serialization/deserialization?
Classes:
// root
public Result Result { get; set; }
// rows
public class Result
{
public List<ResultData> Data { get; set; }
}
//item
public class ResultData
{
[XmlElement(ElementName = "gen_info")]
public GenInfo GenInfo { get; set; }
[XmlElement(ElementName = "hosting")]
public Hosting Hosting { get; set; }
}
Result:
<Result>
<Id>1</Id>
<Data>
<ResultData> <--- REMOVE THIS
<gen_info>
<ascii-name>sadsad</ascii-name>
</gen_info>
<hosting/>
</ResultData> <--- REMOVE THIS
</Data>
</Result>
Need:
<Result>
<Id>1</Id>
<Data>
<gen_info>
<ascii-name>sadsad</ascii-name>
</gen_info>
<hosting/>
</Data>
</Result>
<Result>
<Id>2</Id>
<Data>
<gen_info>
<ascii-name>sadsad2</ascii-name>
</gen_info>
<hosting/>
</Data>
</Result>
This should do but is verbose. Try [XmlElement(ElementName = "gen_info")] on ResultData property first, if it doesn't work:
public class Result
{
[XmlIgnore]
public List<ResultData> Data { get; set; }
[XmlElement(ElementName = "gen_info")]
public ResultData[] __XmlSerializedData{
get{ return Data.ToArray();}
set{ Data = new List<ResultData>(value);}
}
}

Problem with Serialization/Deserialization an XML containing CDATA attribute

I need to deserialize/serialize the xml file below:
<items att1="val">
<item att1="image1.jpg">
<![CDATA[<strong>Image 1</strong>]]>
</item>
<item att1="image2.jpg">
<![CDATA[<strong>Image 2</strong>]]>
</item>
</items>
my C# classes:
[Serializable]
[XmlRoot("items")]
public class RootClass
{
[XmlAttribute("att1")]
public string Att1 {set; get;}
[XmlElement("item")]
public Item[] ArrayOfItem {get; set;}
}
[Serializable]
public class Item
{
[XmlAttribute("att1")]
public string Att1 { get; set; }
[XmlText]
public string Content { get; set; }
}
and everything works almost perfect but after deserialization in place
<![CDATA[<strong>Image 1</strong>]]>
I have
<strong>Image 1</strong>
I was trying to use XmlCDataSection as type for Content property but this type is not allowed with XmlText attribute. Unfortunately I can't change XML structure.
How can I solve this issue?
this should help
private string content;
[XmlText]
public string Content
{
get { return content; }
set { content = XElement.Parse(value).Value; }
}
First declare a property as XmlCDataSection
public XmlCDataSection ProjectXml { get; set; }
in this case projectXml is a string xml
ProjectXml = new XmlDocument().CreateCDataSection(projectXml);
when you serialize your message you will have your nice format (notice )
<?xml version="1.0" encoding="utf-16"?>
<MessageBase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Message_ProjectStatusChanged">
<ID>131</ID>
<HandlerName>Plugin</HandlerName>
<NumRetries>0</NumRetries>
<TriggerXml><![CDATA[<?xml version="1.0" encoding="utf-8"?><TmData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="9.0.0" Date="2012-01-31T15:46:02.6003105" Format="1" AppVersion="10.2.0" Culture="en-US" UserID="0" UserRole=""><PROJECT></PROJECT></TmData>]]></TriggerXml>
<MessageCreatedDate>2012-01-31T20:28:52.4843092Z</MessageCreatedDate>
<MessageStatus>0</MessageStatus>
<ProjectId>0</ProjectId>
<UserGUID>8CDF581E44F54E8BAD60A4FAA8418070</UserGUID>
<ProjectGUID>5E82456F42DC46DEBA07F114F647E969</ProjectGUID>
<PriorStatus>0</PriorStatus>
<NewStatus>3</NewStatus>
<ActionDate>0001-01-01T00:00:00</ActionDate>
</MessageBase>
Most of the solutions presented in StackOverflow works only for Serialization, and not Deserialization. This one will do the job, and if you need to get/set the value from your code, use the extra property PriceUrlByString that I added.
private XmlNode _priceUrl;
[XmlElement("price_url")]
public XmlNode PriceUrl
{
get
{
return _priceUrl;
}
set
{
_priceUrl = value;
}
}
[XmlIgnore]
public string PriceUrlByString
{
get
{
// Retrieves the content of the encapsulated CDATA
return _priceUrl.Value;
}
set
{
// Encapsulate in a CDATA XmlNode
XmlDocument xmlDocument = new XmlDocument();
this._priceUrl = xmlDocument.CreateCDataSection(value);
}
}

How do you avoid creating multiple instances of an object with XML Deserialization?

I've got a class that when serialized to XML looks like this (generalized for simplicity):
<root>
<resources>
<resource name="foo" anotherattribute="value">data</resource>
<resource name="bar" anotherattribute="value">more data</resource>
</resource>
<myobject name="objName">
<resource name="foo" />
</myobject>
</root>
When it's deserialized, I need the instance of resource referenced in the property of the myobject instance to be the same object created during the deserialization of the resources collection. Also, if possible I don't want to have to output the full serialization of the resource instance in myobject, only the name.
Is there any way of doing this? Right now I'm considering resorting to having a separate string property for serialization purposes that gets the relevant object from root when the deserializer sets the property, but that means giving myobject a reference to the root that contains it, and I was hoping to avoid that coupling.
You can't do that with XmlSerializer, because it doesn't handle object references.
If you don't have any constraint on the generated schema, you could use DataContractSerializer, which also serializes to XML but supports references. To use DataContractSerializer, each type must have a DataContract attribute, and each member you want to serialize must have a DataMember attribute :
[DataContract(Name = "root")]
public class root
{
[DataMember]
public List<resource> resources { get; set; }
[DataMember]
public myobject myobject { get; set; }
}
[DataContract]
public class myobject
{
[DataMember]
public string name { get; set; }
[DataMember]
public resource resource { get; set; }
}
[DataContract(Name = "resource", IsReference = true)]
public class resource
{
[DataMember]
public string name { get; set; }
[DataMember]
public string anotherattribute { get; set; }
[DataMember]
public string content { get; set; }
}
...
var serializer = new DataContractSerializer(typeof(root));
using (var xwriter = XmlWriter.Create(fileName))
{
serializer.WriteObject(xwriter, r);
}
Note the IsReference = true for the resource class: that's what makes the serializer handle this class by reference. In the generated XML, each resource instance is only serialized once:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
<myobject>
<name>objName</name>
<resource z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<anotherattribute>value</anotherattribute>
<content>data</content>
<name>foo</name>
</resource>
</myobject>
<resources>
<resource z:Ref="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" />
<resource z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<anotherattribute>value</anotherattribute>
<content>more data</content>
<name>bar</name>
</resource>
</resources>
</root>

Categories