Reputation: 303
I am deserializing an object from xml, but the strings in KeywordList and ResponseList always end up empty.
Tried lots of things and can't seem to get it right. If I loop through it with a reader then the values show up.
using System;
using System.Collections.Specialized;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(ElizaResponses));
using (XmlReader reader = XmlReader.Create("eliza.xml"))
{
ElizaResponses responses = (ElizaResponses)serializer.Deserialize(reader);
reader.Close();
// This reads in all data
//StreamReader reader = new StreamReader("eliza.xml");
//reader.ReadToEnd();
//reader.MoveToContent();
//while (reader.Read())
//{
// if(reader.NodeType == XmlNodeType.Text)
// {
// Console.WriteLine("{0}, {1}", reader.NodeType, reader.Value);
// }
// else
// {
// Console.WriteLine("{0}, {1}", reader.NodeType, reader.Name);
// }
//}
}
Console.ReadLine();
}
}
[Serializable]
[XmlRoot("ElizaResponses")]
[XmlType("ElizaResponses")]
public sealed class ElizaResponses
{
ElizaConversation[] chatList;
public ElizaConversation[] ChatList
{
get { return this.chatList; }
set { this.chatList = value; }
}
}
[Serializable]
public sealed class ElizaConversation
{
// Tried List<string>, string[], StringCollection
StringCollection keywordList = new StringCollection();
StringCollection responseList = new StringCollection();
// Tried [XmlArray], [XmlElement]
[XmlElement("KeywordList")]
[XmlArrayItem("string", typeof(string))]
StringCollection KeywordList
{
get { return this.keywordList; }
set { this.keywordList = value; }
}
[XmlArray("ResponseList")]
[XmlArrayItem("string", typeof(string))]
StringCollection ResponseList
{
get { return this.responseList; }
set { this.responseList = value; }
}
}
}
Here is the example xml
<?xml version="1.0" encoding="utf-8"?>
<ElizaResponses>
<ChatList>
<ElizaConversation>
<KeywordList>
<string>ok</string>
</KeywordList>
<ResponseList>
<string>cool.</string>
<string>great.</string>
<string>:)</string>
</ResponseList>
</ElizaConversation>
<ElizaConversation>
<KeywordList>
<string>shutup</string>
<string>shut up</string>
</KeywordList>
<ResponseList>
<string>make me.</string>
<string>no I won't.</string>
</ResponseList>
</ElizaConversation>
</ChatList>
</ElizaResponses>
Should add I get no exceptions and have turned up the error messaging in the app.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.diagnostics>
<switches>
<add name="XmlSerialization.Compilation" value="4" />
</switches>
</system.diagnostics>
</configuration>
Upvotes: 0
Views: 136
Reputation: 116785
Rather than continuing to attempt to hand-generate your types, you should start by auto-generating them and verifying the auto-generated types work. Only then, simplify as needed. If you post your XML to https://xmltocsharp.azurewebsites.net/, you can generate classes that will deserialize your XML:
[XmlRoot(ElementName = "KeywordList")]
public class KeywordList
{
[XmlElement(ElementName = "string")]
public List<string> String { get; set; }
}
[XmlRoot(ElementName = "ResponseList")]
public class ResponseList
{
[XmlElement(ElementName = "string")]
public List<string> String { get; set; }
}
[XmlRoot(ElementName = "ElizaConversation")]
public class ElizaConversation
{
[XmlElement(ElementName = "KeywordList")]
public KeywordList KeywordList { get; set; }
[XmlElement(ElementName = "ResponseList")]
public ResponseList ResponseList { get; set; }
}
[XmlRoot(ElementName = "ChatList")]
public class ChatList
{
[XmlElement(ElementName = "ElizaConversation")]
public List<ElizaConversation> ElizaConversation { get; set; }
}
[XmlRoot(ElementName = "ElizaResponses")]
public class ElizaResponses
{
[XmlElement(ElementName = "ChatList")]
public ChatList ChatList { get; set; }
}
You can verify using your code above that this version of ElizaResponses
will deserialize your XML. However, these can be simplified.
Firstly, merge KeywordList
and ResponseList
into StringList
:
public class StringList
{
[XmlElement(ElementName = "string")]
public List<string> String { get; set; }
}
[XmlRoot(ElementName = "ElizaConversation")]
public class ElizaConversation
{
[XmlElement(ElementName = "KeywordList")]
public StringList KeywordList { get; set; }
[XmlElement(ElementName = "ResponseList")]
public StringList ResponseList { get; set; }
}
Next, eliminate StringList
entirely replacing it with List<string<>
. Since an extra level of container class is being eliminated, the two [XmlElement]
attributes will need to replaced with [XmlArray]
and [XmlArrayItem]
resulting in the following final versions:
[XmlRoot(ElementName = "ElizaConversation")]
public class ElizaConversation
{
[XmlArray(ElementName = "KeywordList")]
[XmlArrayItem(ElementName = "string")]
public List<string> KeywordList { get; set; }
[XmlArray(ElementName = "ResponseList")]
[XmlArrayItem(ElementName = "string")]
public List<string> ResponseList { get; set; }
}
[XmlRoot(ElementName = "ChatList")]
public class ChatList
{
[XmlElement(ElementName = "ElizaConversation")]
public List<ElizaConversation> ElizaConversation { get; set; }
}
[XmlRoot(ElementName = "ElizaResponses")]
public class ElizaResponses
{
[XmlElement(ElementName = "ChatList")]
public ChatList ChatList { get; set; }
}
Your initial attempt included the following problems:
StringCollection
should be avoided.[XmlArrayItem("Item", typeof(string))]
declarations, the name "Item"
is wrong. It should have been "string"
.[XmlElement]
cannot be combined with [XmlArrayItem]
.KeywordList
and ResponseList
are not public. XmlSerializer
only serializes public members.Sample fiddle.
Upvotes: 1
Reputation: 303
Found the answer. The properties can't be set because they are not public.
Upvotes: 0