I need to deserialize XML file to an object in C#:
<?xml version="1.0" encoding="utf-16"?>
<Test xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance>
<Number>110658419900</Number>
<WorkorderName>2103477915XVN35S_FR_LEFTX111</WorkorderName>
<RequestDate>2022-10-13T16:53:13.2171314+02:00</RequestDate>
<ShelfNumber>4</ShelfNumber>
</Test>
public class Test
{
public string Number { get; set; }
public string WorkorderName { get; set; }
public string RequestDate { get; set; }
public string ShelfNumber { get; set; }
}
I am using this approach:
try
{
XmlSerializer serializer = new XmlSerializer(typeof(Test));
StreamReader reader = new StreamReader(fileSystemEventArgs.FullPath);
Test test = (Test)serializer.Deserialize(reader);
reader.Close();
return test;
}
catch (Exception ex)
{
string message = ex.Message;
}
But I am receiving an error:
{"There is an error in XML document (2, 17)."}
Everything is working If I remove this from XML:
xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
I don't know why this is happening. How to solve this issue? How to ignore this xmls:xsd and xmls:xsi?
That "xml" isn't valid xml, and the parser is correct to shout here. The xml should start (note the quotes):
<Test xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
(etc)
However, those are just namespace alias declarations, and those aliases are never used, so: you can also just delete them here, leaving your xml as starting
<Test>
Related
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"?
I need to deserialize XML that uses a field "type" to indicate what content to expect.
Type 0 says that I can expect simple text whilst type 1 indicates that the content is of a more complex structure.
I know that I could write some custom deserialization mechanism but would like to know whether there was any builtin way to solve this.
Since the XMLSerializer expects a string it simply throws away the content in case it is XML. This stops me from running the content deserialization as a second step.
<Msg>
<MsgType>0</MsgType>
<Data>Some text</Data>
</Msg>
<Msg>
<MsgType>1</MsgType>
<Data>
<Document>
<Type>PDF</Type>
.....
</Document>
</Data>
</Msg>
That isn't supported out of the box; however, you could perhaps use:
public XmlNode Data {get;set;}
and run the "what to do with Data?" as a second step, once you can look at MsgType.
Complete example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
static class P
{
static void Main()
{
const string xml = #"<Foo>
<Msg>
<MsgType>0</MsgType>
<Data>Some text</Data>
</Msg>
<Msg>
<MsgType>1</MsgType>
<Data>
<Document>
<Type>PDF</Type>
.....
</Document>
</Data>
</Msg>
</Foo>";
var fooSerializer = new XmlSerializer(typeof(Foo));
var docSerializer = new XmlSerializer(typeof(Document));
var obj = (Foo)fooSerializer.Deserialize(new StringReader(xml));
foreach (var msg in obj.Messages)
{
switch (msg.MessageType)
{
case 0:
var text = msg.Data.InnerText;
Console.WriteLine($"text: {text}");
break;
case 1:
var doc = (Document)docSerializer.Deserialize(new XmlNodeReader(msg.Data));
Console.WriteLine($"document of type: {doc.Type}");
break;
}
Console.WriteLine();
}
}
}
public class Foo
{
[XmlElement("Msg")]
public List<Message> Messages { get; } = new List<Message>();
}
public class Message
{
[XmlElement("MsgType")]
public int MessageType { get; set; }
public XmlNode Data { get; set; }
}
public class Document
{
public string Type { get; set; }
}
I need some help regarding deserialization of this kind of xml in C#:
<Request>
<AccountStage att1="419749" att2="575474" att3="800177" att4="096057" att5="917185" att6="017585" att7="huKuBgcQ" att8="stgs10" att9="ACTIVE" att10="2" att11="2"/>
</Request>
If I use the "Special paste" feature from VS, and convert the request as xml classes, when I want to use the request and send it to the server, it changes the format as follows:
<Request>
<AccountStage>
<att1>22222</att1>
<att2>22222</att2>
<att3>22222</att3>
<att4>2</att4>
<att5>2</att5>
<att6>22222</att6>
<att7>Ion</att7>
<att8>agg3</att8>
<att9>ACTIVE</att9>
<att10>2</att10>
<att11>2</att11>
</AccountStage>
</Request>
Use XmlAttribute to specify how members should be defined/interpreted:
using System.IO;
using System.Xml.Serialization;
namespace WpfApp2
{
internal class Test
{
private readonly string xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<Request>
<AccountStage att1=""419749"" att2=""575474"" att3=""800177"" att4=""096057"" att5=""917185"" att6=""017585"" att7=""huKuBgcQ""
att8=""stgs10"" att9=""ACTIVE"" att10=""2"" att11=""2"" />
</Request>";
public Test()
{
Request request;
// serialize
var serializer = new XmlSerializer(typeof(Request));
using (var reader = new StringReader(xml))
{
request = (Request) serializer.Deserialize(reader);
}
// deserialize
request.AccountStage.Attribute1 = "abcd";
using (var writer = new StringWriter())
{
serializer.Serialize(writer, request);
var s = writer.ToString();
}
}
}
public class Request
{
public AccountStage AccountStage { get; set; }
}
public class AccountStage
{
[XmlAttribute("att1")]
public string Attribute1 { get; set; }
}
}
Result
<?xml version="1.0" encoding="utf-16"?>
<Request xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AccountStage att1="abcd" />
</Request>
I have 2 classes as defined below:
[Serializable()]
public class Topology
{
[XmlElement("floors")]
public Floor[] Floors { get; set; }
}
[Serializable()]
public class Floor
{
[XmlElement("name")]
public string name { get; set; }
[XmlElement("map_path")]
public string map_path { get; set; }
}
I want to deserialize the xml file shown below and i use the below specified method to deserialize the xml file.
XMLFile:
<?xml version="1.0" encoding="iso-8859-9"?>
<Topology>
<floors>
<floor id="1">
<name>1</name>
<map_path>C:\</map_path>
</floor>
<floor id="2">
<name>2</name>
<map_path>D:\</map_path>
</floor>
</floors>
</Topology>
Deserialize Method:
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(Topology));
StreamReader reader = new StreamReader(#"C:\topology2.xml");
Topology top = (Topology)serializer.Deserialize(reader);
reader.Close();
for (int i = 0; i < top.Floors.Length; i++ )
Console.WriteLine(top.Floors[i].name + top.Floors[i].map_path);
Console.ReadLine();
}
I can get "Floors" but i couldn't get the name and map_path node values. What should i do?
Your XML file is not properly formatet for the xml serializer to read. Please follow the following formating:
<?xml version="1.0" encoding="iso-8859-9"?>
<Topology>
<floors id="1">
<name>1</name>
<map_path>C:\</map_path>
</floors>
<floors id="2">
<name>1</name>
<map_path>C:\</map_path>
</floors>
</Topology>
I have a problem with CDATA deserialization using standard .Net XmlSerializer.
Update: I get XML from external system and I can't influence it's format so I can't make CData be enclosed in a separate Element of Attribute.
Serialization gives this:
<?xml version="1.0" encoding="utf-16"?>
<MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><![CDATA[Hello, world!]]></MyClass>
Deserialization does not restore object to it's original state.
Here's class that is being serialized:
public class MyClass
{
string _data;
[XmlIgnore]
public string Data
{
get { return _data; }
set { _data = value; }
}
[XmlAnyElement]
public XmlCDataSection CData
{
get { return new XmlDataDocument().CreateCDataSection(Data); }
set { Data = value.Value; }
}
}
Here's the test which fails:
[Test]
public void CData_as_inner_text_test()
{
MyClass item = new MyClass();
item.Data = "Hello, world!";
XmlSerializer serializer = new XmlSerializer(item.GetType());
string serialized;
using (StringWriter sw = new StringWriter())
{
serializer.Serialize(sw, item);
serialized = sw.GetStringBuilder().ToString();
}
MyClass deserialized;
using (StringReader sr = new StringReader(serialized))
{
deserialized = (MyClass)serializer.Deserialize(sr);
}
Assert.AreEqual(item.Data, deserialized.Data); // For some reason, deserialized.Data == null
}
I found the same problem here but there's no answer:
XmlSerializer, XmlAnyElement and CDATA
The CData property ends up null, because the content of the CDATA section ends up in the Data property, where it is being ignored...
<MyClass><![CDATA[Hello, world!]]></MyClass>
is absolutely equivalent to:
<MyClass>Hello, world!</MyClass>
You shouldn't care whether the external app writes the content of MyClass as CData or not. Likewise, the external app shouldn't care how you write it out.
IOW, this should be all you need:
public class MyClass
{
string _data;
[XmlText]
public string Data
{
get { return _data; }
set { _data = 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>