XML Deserialization without specifying XmlRootAttribute - c#

here is my xml :
<connections total="2" >
<person>
<id>ohKiUAZWz2</id>
<first-name>ミ★нιяαℓ</first-name>
<last-name>§|-|ä|-|»♥«</last-name>
<headline>--</headline>
</person>
<person>
<id>LmgYe-Nl2a</id>
<first-name>kunal</first-name>
<last-name>b</last-name>
<headline>Student at MscIT,Surat</headline>
</person>
</connection>
from code behind :
List<LinkWall> LinkWallList = new List<LinkWall>();
XmlNodeList xmlnode = doc.GetElementsByTagName("person");
foreach (XmlElement ele in xmlnode)
{
XmlRootAttribute xr = new XmlRootAttribute("person");
XmlSerializer mySerializer = new XmlSerializer(typeof(LinkWall),xr);
StringReader re = new StringReader(ele.InnerXml);
LinkWallList.Add((LinkWall)mySerializer.Deserialize(re));
}
here is my class definition :
[XmlRoot("person")]
public class LinkWall
{
public LinkWall()
{ }
[XmlElement(ElementName = "id")]
public string id { get; set; }
[XmlElement(ElementName = "first-name")]
public string firstName { get; set; }
[XmlElement(ElementName = "last-name")]
public string lastName { get; set; }
[XmlElement(ElementName = "headline", IsNullable=true)]
public string headline { get; set; }
}
but when i try to deserialize. it show me error like : {"There are multiple root elements."}
is there any solution or alternative for specifying XmlRootAttribute ?
thanks in advance, Milan Mendpara

I think your issue is with this line:
StringReader re = new StringReader(ele.InnerXml);
Change it to:
StringReader re = new StringReader(ele.OuterXml);
The reason is the InnerXml property will return all of the child nodes but not the parent node. OuterXml will include your parent person node too.
i.e. InnerXml has no root element (well, it has many!):
<id>ohKiUAZWz2</id>
<first-name>?????al</first-name>
<last-name>§|-|ä|-|»?«</last-name>
<headline>--</headline>
OuterXml is as expected:
<person>
<id>ohKiUAZWz2</id>
<first-name>?????al</first-name>
<last-name>§|-|ä|-|»?«</last-name>
<headline>--</headline>
</person>
There is also no real need to use the XmlSerializer constructor you are using. Try:
XmlSerializer mySerializer = new XmlSerializer(typeof(LinkWall));
Instead.

Try OuterXml instead of InnerXML
StringReader re = new StringReader(ele.OuterXml);

I believe you should make a class structured like your xml file and deserialize your xml file into an instance of this class.
MyClass myObject = new MyClass;
XmlSerializer ser = new XmlSerializer(myObject.GetType());
using (FileStream fs = new FileStream(FilePath, FileMode.Open))
{
XmlTextReader reader = new XmlTextReader(fs);
myObject = (MyClass)ser.Deserialize(reader);
}
This code runs faster and then you will be able to do wathever you want with the data inside your object.

Related

Unable to deserialize the kml

I have the following Kml:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Trains</name>
<description/>
<name>Red Train</name>
</Document>
</kml>
and the following code to deserialize it
private void KmlToObject()
{
var path = #"C:\Users\Downloads\test.kml";
var serializer = new XmlSerializer(typeof(Kml));
using var reader = new StringReader(path);
var obj = serializer.Deserialize(reader) as Kml;
}
[XmlRoot(ElementName = "kml")]
public class Kml
{
[XmlElement(ElementName = "Document")]
public object Document { get; set; }
[XmlAttribute(AttributeName = "xmlns")]
public string Xmlns { get; set; }
}
And I get the following error:
There is an error in XML document (1, 1).
What am I doing wrong?
StringReader is not the way to read the file.
Initializes a new instance of the StringReader class that reads from the specified string.
Instead, you should look for StreamReader with the ReadToEnd method. Reference: How to: Read text from a file
var path = #"C:\Users\Downloads\test.kml";
var serializer = new XmlSerializer(typeof(Kml));
using (StreamReader sr = new StreamReader(path))
{
var obj = serializer.Deserialize(sr.ReadToEnd()) as Kml;
}
And provide the Namespace to XmlRoot attribute.
[XmlRoot(ElementName = "kml", Namespace = "http://www.opengis.net/kml/2.2")]
public class Kml
{
...
}
Your input file is not valid KML. A Document tag can only contain one name tag, and it looks like yours contains a name, an empty description, and then another name tag. Maybe you intended for the Document to contain a Placemark tag and have that contain the name "Red Train"?

c# Deserializing xml to class "xmlns was not expected"

I want to deserialize a XML node to a class, with all the subnodes values into class properties
I got this error
ex {"There is an error in XML document (1, 2)."} System.Exception {System.InvalidOperationException}
and the message of the exception
InnerException {"<LITERALS xmlns=''> was not expected."} // If i use InnerXml it would be REVISION xmlns...
I tried Outer and Inner XML with a lot of solutions that appear in stackoverflow.
I dont know why it adds xmlns
My xml is like that:
<root>
<LITERALS>
<REVISION>Rev.</REVISION>
<SERIE>Serie</SERIE>
</LITERALS>
<MORENODES></MORENODES>
<MORENODES></MORENODES>
</root>
And my class Literals to deserialize the xml node
{
// I tried these options that i saw in a post
// [XmlRoot(ElementName="LITERALS")]
// [Serializable, XmlRoot("LITERALS")]
[XmlRoot(Namespace = "www.idk.com", ElementName = "LITERALS", DataType = "string", IsNullable = true)]
public class Literals
{
[XmlElement(ElementName = "REVISION")]
public string REVISION { get; set; }
[XmlElement(ElementName = "SERIE")]
public string SERIE { get; set; }
}
}
My code
XmlNode literalsNodo = courseNodo.SelectSingleNode("LITERALS");
XmlRootAttribute xRoot = new XmlRootAttribute("LITERALS");
xRoot.ElementName = "LITERALS";
xRoot.Namespace = "http://www.idk.com";
xRoot.IsNullable = true;
if (literalsNodo != null)
{
XmlSerializer xs = new XmlSerializer(typeof(Literals),xRoot);
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(literalsNodo.InnerXml));
literals = (Literals)xs.Deserialize(ms);
}

How to bind XML file to List<MyClass>?

I've been using the answer here
binding xml elements to model in MVC4
to bind an XML file to a model.
This works fine when the XML file has one element. I need to handle the case when there are many elements. I'd like all of those elements to go into a List.
Here's an example file:
<root>
<item>
<firstname>Tom</firstname>
</lastname>Jones</lastname>
<item>
<item>
<firstname>Jane</firstname>
</lastname>Doe</lastname>
</item>
</root>
MyXMLElements class looks like:
[Serializable]
[XmlRoot("item")]
public class MyXMLElements
{
public string first name {get;set;}
public string lastname {get;set;}
}
How I do I create a List<MyXMLElements>?
I think the easiest way is to use the XmlSerializer:
XmlSerializer serializer = new XmlSerializer(typeof(List<MyClass>));
using(FileStream stream = File.OpenWrite("filename"))
{
List<MyClass> list = new List<MyClass>();
serializer.Serialize(stream, list);
}
using(FileStream stream = File.OpenRead("filename"))
{
List<MyClass> dezerializedList = (List<MyClass>)serializer.Deserialize(stream);
}
You can achieve it this way (I'm reading XML from a file, but you can get it from other source):
XDocument xDoc = XDocument.Load(#"C:\new.xml");
List<MyXMLElements> list = (from xEle in xDoc.Descendants("item")
select new MyXMLElements() { firstname = xEle.Element("firstname").Value, lastname = xEle.Element("lastname").Value }).ToList();
You don't need XmlRoot in this case.
XElement xelement = XElement.Load("..\\..\\XML.xml");
IEnumerable<XElement> employees = xelement.Elements();
Console.WriteLine("List of all Employee Names :");
foreach (var employee in employees)
{
Console.WriteLine(employee.Element("firstname").Value + employee.Element("lastname").Value );
}
A solution is given below:
The class should look like this:
[Serializable]
[XmlType(TypeName = "item")]
public class MyXMLElements
{
public string firstname {get;set;}
public string lastname {get;set;}
}
The deserialization code is below:
using (var rdr = System.Xml.XmlReader.Create(#"input.xml"))
{
var root=new System.Xml.Serialization.XmlRootAttribute("root");
var ser = new System.Xml.Serialization.XmlSerializer(typeof(List<MyXMLElements>),root);
var list=(List<MyXMLElements>)ser.Deserialize(rdr);
}

How to include null properties during xml serialization

Currently, the code below omits null properties during serialization. I want null valued properties in the output xml as empty elements. I searched the web but didn't find anything useful. Any help would be appreciated.
var serializer = new XmlSerializer(application.GetType());
var ms = new MemoryStream();
var writer = new StreamWriter(ms);
serializer.Serialize(writer, application);
return ms;
Sorry, I forgot to mention that I want to avoid attribute decoration.
Can you control the items that have to be serialized?
Using
[XmlElement(IsNullable = true)]
public string Prop { get; set; }
you can represent it as <Prop xsi:nil="true" />
You can use also use the following code. The pattern is ShouldSerialize{PropertyName}
public class PersonWithNullProperties
{
public string Name { get; set; }
public int? Age { get; set; }
public bool ShouldSerializeAge()
{
return true;
}
}
PersonWithNullProperties nullPerson = new PersonWithNullProperties() { Name = "ABCD" };
XmlSerializer xs = new XmlSerializer(typeof(nullPerson));
StringWriter sw = new StringWriter();
xs.Serialize(sw, nullPerson);
XML
<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
www.w3.org/2001/XMLSchema">
<Name>ABCD</Name>
<Age xsi:nil="true" />
</Person>
Set the XmlElementAttribute.IsNullable property:
https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute.isnullable(v=vs.110).aspx

Add root element attribute

I'm serializing a class like below
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
StringWriter sw = new StringWriter();
XmlSerializer serializer1 = new XmlSerializer(typeof(List<student>), new XmlRootAttribute("Response"));
XmlTextWriter xmlWriter = new XmlTextWriter(sw);
serializer1.Serialize(xmlWriter, ls, namespaces);
sw.ToString()
The result string below
<?xml version="1.0" encoding="utf-16"?>
<Response><student><name>xxx</name></student></Response>
but, How can i add an attribute to the root element(Response)?
like below one
<?xml version="1.0" encoding="utf-16"?>
<Response status="1"><student><name>xxx</name></student></Response>
You just need to mark that property of the class with XmlAttribute, i.e.
class MyClass{
[XmlAttribute("status")]
public string ErrorStatus { get; set; }
}
Edit:
Just realised you are serializing the list directly. Put your list inside a parent class, Response, and add the above attribute to this Response class, then serialise the Response object.
Hope this helps.
You can create another object that contains the list, and then create a property to add the attribute to the root node.
The trick is to preface the list in this new class with an explicit type assignment to the Student type to avoid having your list nested within another parent node.
[XmlType(TypeName = "Response")]
public class ResponseObject
{
[XmlAttribute("status")]
public string file { get; set; }
[XmlElement("Student", Type = typeof(Student))]
public List<Student> studentList { get; set; }
}
Your code would then look like the following
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
StringWriter sw = new StringWriter();
XmlSerializer serializer1 = new XmlSerializer(typeof(ResponseObject));
XmlTextWriter xmlWriter = new XmlTextWriter(sw);
//Creating new object and assign the existing list and status
ResponseObject resp = new ResponseObject();
resp.studentList = ls;
resp.status = 1;
//Serialize with the new object
serializer1.Serialize(xmlWriter, resp, namespaces);
sw.ToString()

Categories

Resources