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"?
Related
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);
}
In app a get a response from vk server with information about user's playlist in xml. App throw InvalidOperationexception here
var result = (PlayList)serializer.Deserialize(reader);
DTOs:
public class PlayList
{
[XmlElement("audio")]
public List<Song> Audio { get; set; }
public PlayList()
{
Audio = new List<Song>();
}
}
public class Song
{
[XmlElement(ElementName ="id")]
public int Id { get; set; }
...
[XmlElement(ElementName ="genre_id")]
public int Genre_id { get; set; }``
}
But my code work when I delete this 3 lines from xmlfile
<response>
<count>156</count>
...
<response>
and <items list="true"> -> <items>
What I must change in my code to make it work?
var serializer = new XmlSerializer(typeof(PlayList), new XmlRootAttribute("items"));
using (var stringReader = new StringReader(xml))
using (var reader = XmlReader.Create(stringReader))
{
var result = (PlayList)serializer.Deserialize(reader);
Console.WriteLine(result.Audio[1].Title);
}
And this is an example of xml.
How do I Deserialize this XML document?
var xml =
#"<?xml version="1.0" encoding="utf-8"?>
<response>
<count>156</count>
<items list="true">
<audio>
<id>456239034</id>
<owner_id>181216176</owner_id>
<artist>Oh Wonder</artist>
<title>Technicolour Beat</title>
<duration>179</duration>
<date>1465249779</date>
<url>http://cs613222.vk.me/u285269348/audios/4ae051b98797.mp3?extra=MS3dvwutPkFx7k8rQdV3Szuh7cSwLkRcS_KpPbO9DXviMFLNNgkDAmZFWdIueioL3dDgdPUc7rch0V81KgOHYaTTSampaRcljxrJcytJYImZssivVP7DigKdcxaLoALeUatAhuHk5gXQ7TY</url>
<lyrics_id>235824304</lyrics_id>
<genre_id>1001</genre_id>
</audio>
<audio>
<id>456239033</id>
<owner_id>181216176</owner_id>
<artist>Mikky Ekko</artist>
<title>We Must Be Killers (Волчонок / Teen Wolf / 2х08) </title>
<duration>195</duration>
<date>1465249755</date>
<url>http://cs521610.vk.me/u14558277/audios/c2daca7b2b6f.mp3?extra=z9VPdKf6v- n7zkIfZ_6ej-RZSjlIjAr_qYmVp4F-zI1Z3ZXgVtOUElovlOiSOgSuKbFC0e0ahac8XU-AxNtfEYYPe5gcejSotr84mHi0LQ2L-b0BPWP2cYn5Yy44YN4FLPNKq0Ow8vMKFn0</url>
<lyrics_id>26311225</lyrics_id>
</audio>
</items>
</response>";
You need to let it know its an array, I think using typeof(PlayList[]) instead of typeof(PlayList)
You can just skip unnecessary nodes with the XmlReader.
using (var reader = XmlReader.Create(stringReader))
{
reader.ReadToFollowing("items");
var result = (PlayList)serializer.Deserialize(reader);
I am loading my data from XML using C# this way:
XmlDocument xmlDoc = new XmlDocument();
TextAsset xmlFile = Resources.Load("levels/" + levelID) as TextAsset;
xmlDoc.LoadXml(xmlFile.text);
XmlNodeList levelsList = xmlDoc.GetElementsByTagName("level");
foreach (XmlNode levelInfo in levelsList)
{
XmlNodeList childNodes = levelInfo.ChildNodes;
foreach (XmlNode value in childNodes)
{
switch (value.Name)
{
case "info":
//levelWidth = getInt(value, 0);
//levelHeight = getInt(value, 1);
break;
}
}
}
And heres XML I am loading:
<?xml version="1.0" encoding="utf-8" ?>
<level>
<info w="1000" h="500"/>
</level>
It works just fine, I am now trying to find best way to load child nodes, inside my level node with multiple points nodes inside
<?xml version="1.0" encoding="utf-8" ?>
<level>
<info w="1000" h="500"/>
<ground>
<point val1="val1" val2="val2"/>
</ground>
</level>
I will be grateful for some guidance how to move in the right direction, thank you.
Using XML Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<level>" +
"<info w=\"1000\" h=\"500\"/>" +
"</level>";
XDocument doc = XDocument.Parse(xml);
XElement level = (XElement)doc.FirstNode;
level.Add("ground", new object[] {
new XElement("point", new XAttribute[] {
new XAttribute("val1", "val1"),
new XAttribute("val2", "val2")
})
});
}
}
}
If you need read all points, you can use
var nodeList = Xmldocument.SelectNodes("level/info/ground/point");
SelectNodes return a list of nodes.
I would go for a slidely different way and use a data object. Then you don't have to analyse xml, you just code your data class:
[Serializable()]
public class CLevel
{
public string Info { get; set; }
}
[Serializable()]
public class CDatafile
{
public List<CLevel> LevelList { get; set; }
public CDatafile()
{
LevelList = new List<CLevel>();
}
}
public class DataManager
{
private string FileName = "Data.xml";
public CDatafile Datafile { get; set; }
public DataManager()
{
Datafile = new CDatafile();
}
// Load file
public void LoadFile()
{
if (System.IO.File.Exists(FileName))
{
System.IO.StreamReader srReader = System.IO.File.OpenText(FileName);
Type tType = Datafile.GetType();
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
object oData = xsSerializer.Deserialize(srReader);
Datafile = (CDatafile)oData;
srReader.Close();
}
}
// Save file
public void SaveFile()
{
System.IO.StreamWriter swWriter = System.IO.File.CreateText(FileName);
Type tType = Datafile.GetType();
if (tType.IsSerializable)
{
System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
xsSerializer.Serialize(swWriter, Datafile);
swWriter.Close();
}
}
Then you can use it to create, save and load the file like this:
DataManager dataMng = new DataManager();
// Create some data
CLevel level = new CLevel();
level.Info = "Testlevel";
dataMng.Datafile.LevelList.Add(level);
// Save to file
dataMng.SaveFile();
// Load from file
dataMng.LoadFile();
So you can do everything in code checked by the compiler. Makes life a lot easier, or what do you think?
I want to create a serialisable class to represent an xml envelope that can contain arbitrary message content. Example xml (simplified) below:
<?xml version="1.0" encoding="utf-8"?>
<Envelope>
<MessageA>
<Url></Url>
</MessageA>
</Envelope>
<?xml version="1.0" encoding="utf-8"?>
<Envelope>
<MessageB>
<Value></Value>
</MessageB>
</Envelope>
My idea is to use a generic envelope class to handle this:
[Serializable]
[XmlRoot(ElementName="Envelope")]
public class Envelope<TContent> where TContent : new()
{
public Envelope()
{
Content = new TContent();
}
public TContent Content { get; set; }
}
[Serializable]
public class MessageA
{
public string Url { get; set; }
}
[Serializable]
public class MessageB
{
public string Value { get; set; }
}
These could be serialised so:
var envelope = new Envelope<MessageA>();
envelope.Content.Url = "http://www.contoso.com";
string xml = envelope.ToXml();
However, instead of the xml message that I want (per examples above), I get the following. How can I change the classes or the serialisation process to rename the Content element to the name of the Message itself?
<?xml version="1.0" encoding="utf-8"?>
<Envelope>
<Content>
<Url>http://www.contoso.com</Url>
</Content>
</Envelope>
Found that the XmlAttributeOverrides class has a solution for this problem. Adding the following method to the Envelope class causes the ToXml() extension method to serialise the object as required.
public string ToXml()
{
return ToXml(typeof(TContent).Name);
}
public string ToXml(string contentElementName)
{
XmlElementAttribute element = new XmlElementAttribute(contentElementName, typeof(TContent));
XmlAttributes attributes = new XmlAttributes();
attributes.XmlElements.Add(element);
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Envelope<TContent>), "Content", attributes);
return ToXml(this, overrides);
}
public string ToXml(Envelope<TContent> value, XmlAttributeOverrides overrides)
{
using (var sw = new Utf8StringWriter())
{
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = omitXmlDeclaration,
Indent = true
};
XmlSerializer xs = new XmlSerializer(typeof(Envelope<TContent>), overrides);
using (XmlWriter writer = XmlWriter.Create(sw, settings))
{
xs.Serialize(writer, value);
}
return sw.ToString();
}
}
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.