Data ("1.0.0") from attribute "version" fall into property. But the property "Event" in the same class remains empty.
If cut namespace from XML, it will work.
My XML:
<rootnode>
<ns:eventresponse xmlns:ns="somenamespace" version="1.0.0">
<event id="694717028">
<somedata>val</somedata>
</event>
</ns:eventresponse>
</rootnode>
My class:
[XmlRoot("rootnode")]
public class RootNode
{
[XmlElement(ElementName = "eventresponse", Namespace = "somenamespace")]
public EventResponseData EventResponse { get; set; }
}
public class EventResponseData
{
[XmlElement("event")]
public EventData Event { get; set; }
[XmlAttribute("version")]
public string Version { get; set; }
}
public class TvEventData
{
[XmlAttribute("id")]
public string EventID { get; set; }
[XmlElement("somedata")]
public string SomeData { get; set; }
}
My Deserializer:
using (var reader = XmlReader.Create(new StringReader(xml)))
{
reader.MoveToContent();
var obj = (T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
Your event element is implicitly in the same namespace in the XML due to namespace defaulting, so you should specify that in your declaration:
public class EventResponseData
{
[XmlElement(ElementName = "event", Namespace = "somenamespace")]
public EventData Event { get; set; }
[XmlAttribute("version")]
public string Version { get; set; }
}
Related
I'm attempting to deserialize an XML file into corresponding C# objects. I've read through the other answers and I'm at a loss as to what I'm doing wrong.
Here's my XML file
<?xml version="1.0" encoding="utf-8"?>
<DialogueObjectCollection>
<DialogueObjects>
<DialogueObject id="0001">
<name>CHARACTER</name>
<dialogue>
<text tag="1">Hi, this is a message.</text>
<text tag="2">Yup.</text>
<text tag="3">What do you want to do?
<options>
<option action= "1">Go back.</option>
<option action="4">Tell me something new.</option>
</options>
</text>
<text tag= "4">This is the end.</text>
</dialogue>
</DialogueObject>
<DialogueObject id="0002">
<name>CHARACTER2</name>
<dialogue>
<text tag="1">Hi.</text>
</dialogue>
</DialogueObject>
</DialogueObjects>
</DialogueObjectCollection>
Here are my classes:
{
[Serializable(), XmlRoot("DialogueObject")]
public class DialogueObject
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlElement("name")]
public string name { get; set; }
[XmlAttribute("tag")]
public int tag { get; set; }
public OptionHolder option;
public DialogueHolder dialogueHolder { get; set; }
[XmlAttribute("action")]
public string action { get; set; }
}
[Serializable(), XmlRoot("dialogue")]
public class DialogueHolder
{
[XmlArray("dialogue")]
[XmlArrayItem("text", IsNullable = false)]
public TextItem[] dialogue { get; set; }
}
[Serializable(),XmlRoot("text")]
public class TextItem
{
[XmlAttribute]
public string tag { get; set; }
public string text { get; set; }
}
[Serializable(),XmlRoot("option")]
public class OptionHolder
{
[XmlAttribute]
public string action;
[XmlElement("option")]
public string option;
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("DialogueObjectCollection")]
public class DialogueObjectCollection
{
[XmlArray("DialogueObjects")]
[XmlArrayItem("DialogueObject", typeof(DialogueObject))]
public DialogueObject[] dialogueObject { get; set; }
}
And my method:
public static void LoadDialogue()
{
DialogueObjectCollection dialogueCollection = null;
string path = "Content/NPCdata.xml";
XmlSerializer serializer = new XmlSerializer(typeof(DialogueObjectCollection));
Console.WriteLine("LOADDINGGGG");
StreamReader reader = new StreamReader(path);
dialogueCollection = (DialogueObjectCollection)serializer.Deserialize(reader);
//test print Console.WriteLine(dialogueCollection.dialogueObject.First().dialogueHolder.dialogue.First().text);
}
So, it's telling me that dialogueHolder is returning null. I can get the dialogueObject.First().name and id to print. I can't figure out why the dialogue text isn't loading into it. (My attempts at fixing it included adding the XmlRootNode attributes and adding more classes-- I'm new to XML serialization in C#)
Thanks for any help!
try code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication3
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
LoadDialogue(FILENAME);
}
public static void LoadDialogue(string path)
{
XmlReader reader = XmlReader.Create(path);
XmlSerializer serializer = new XmlSerializer(typeof(DialogueObjectCollection));
DialogueObjectCollection dialogueObjectCollection = (DialogueObjectCollection)serializer.Deserialize(reader);
}
}
[Serializable(), XmlRoot("DialogueObject")]
public class DialogueObject
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlElement("name")]
public string name { get; set; }
[XmlAttribute("tag")]
public int tag { get; set; }
public OptionHolder option;
[XmlElement("dialogue")]
public DialogueHolder dialogueHolder { get; set; }
[XmlAttribute("action")]
public string action { get; set; }
}
[Serializable(), XmlRoot("dialogue")]
public class DialogueHolder
{
[XmlElement("text")]
public TextItem[] texItem { get; set; }
}
[Serializable(), XmlRoot("text")]
public class TextItem
{
[XmlAttribute]
public string tag { get; set; }
[XmlText()]
public string text { get; set; }
[XmlArray("options")]
[XmlArrayItem("option")]
public OptionHolder[] options { get; set; }
}
[Serializable(), XmlRoot("option")]
public class OptionHolder
{
[XmlAttribute]
public string action;
[XmlElement("option")]
public string option;
}
[XmlRoot("DialogueObjectCollection")]
public class DialogueObjectCollection
{
[XmlArray("DialogueObjects")]
[XmlArrayItem ("DialogueObject")]
public DialogueObject[] dialogueObject { get; set; }
}
}
There is a problem, that the object fields are initialized as null.
I've checked a couple of examples, I've set the field annotations, but seems like I did something wrong.
So here is my xml file:
<?xml version="1.0" encoding="UTF-8"?>
<getInvoiceReply>
<invoiceID value="944659502"/>
<invFastener>
<fastenerID value=""/>
<fastenerName value=""/>
<fastenerCount value=""/>
<fastenerProperty>
<propID value=""/>
<propName value=""/>
<propValue value=""/>
</fastenerProperty>
</invFastener>
</getInvoiceReply>
I've created the class hierarcy.
Root class InvoiceReply :
[XmlRoot("getInvoiceReply")]
public class InvoiceReply
{
[XmlAttribute("invoiceID")]
public string InvoiceId { get; set; }
[XmlArray("invFastener")]
public List<InvFastener> InvFastener { get; set; }
}
class InvFastener :
public class InvFastener
{
[XmlAttribute("fastenerID")]
public string FastenerID { get; set; }
[XmlAttribute("fastenerName")]
public string FastenerName { get; set; }
[XmlAttribute("fastenerCount")]
public string FastenerCount { get; set; }
[XmlArray("fastenerProperty")]
public List<FastenerProperty> FastenerProperty { get; set; }
}
class FastenerProperty:
public class FastenerProperty
{
[XmlAttribute("propID")]
public string PropId { get; set; }
[XmlAttribute("propName")]
public string PropName { get; set; }
[XmlAttribute("propValue")]
public string PropValue { get; set; }
}
Test code:
InvoiceReply i = null;
var serializer = new XmlSerializer(typeof(InvoiceReply));
using (var reader = XmlReader.Create("C:\\filePathHere\\test.xml"))
{
i = (InvoiceReply)serializer.Deserialize(reader);
}
Could anyone please suggest why is this happens?
You have a few issues with your objects. You are trying to get attributes in place of elements and your arrays are not arrays, they are merely complex elements. Below is a working example that matches your xml schema
class Program
{
static void Main(string[] args)
{
string xml = #"<?xml version=""1.0"" encoding=""UTF-8""?>
<getInvoiceReply>
<invoiceID value=""944659502""/>
<invFastener>
<fastenerID value=""""/>
<fastenerName value=""""/>
<fastenerCount value=""""/>
<fastenerProperty>
<propID value=""""/>
<propName value=""""/>
<propValue value=""""/>
</fastenerProperty>
</invFastener>
</getInvoiceReply>";
var serializer = new XmlSerializer(typeof(InvoiceReply));
var i = (InvoiceReply)serializer.Deserialize(new MemoryStream(System.Text.Encoding.UTF8.GetBytes(xml)));
Console.ReadKey();
}
}
//Generic class for getting value attribute
public class ValueElement
{
[XmlAttribute("value")]
public string Value { get; set; }
}
[XmlRoot("getInvoiceReply")]
public class InvoiceReply
{
[XmlElement("invoiceID")]
public ValueElement InvoiceId { get; set; } //This is a value element
[XmlElement("invFastener")]
public List<InvFastener> InvFastener { get; set; } //This is an element, not an array
}
public class InvFastener
{
[XmlElement("fastenerID")]
public ValueElement FastenerID { get; set; }//This is a value element
[XmlElement("fastenerName")]
public ValueElement FastenerName { get; set; }//This is a value element
[XmlElement("fastenerCount")]
public ValueElement FastenerCount { get; set; }//This is a value element
[XmlElement("fastenerProperty")]
public List<FastenerProperty> FastenerProperties { get; set; } //This is an element, not an array
}
public class FastenerProperty
{
[XmlElement("propID")]
public ValueElement PropId { get; set; }//This is a value element
[XmlElement("propName")]
public ValueElement PropName { get; set; }//This is a value element
[XmlElement("propValue")]
public ValueElement PropValue { get; set; }//This is a value element
}
I wonder how to implement the method ReadXml of the IXmlSerializable interface when my XML contains recursive tags like in the following example:
<?xml version='1.0' encoding='utf-8'?>
<dform>
<label name='label-a' text='A' dbpath='module/label-a'/>
<textmemo name='textmemo-a' text='' dbpath='module/textmemo-a'/>
<section name='section-a' text='' dbpath='module/section-a'>
<textmemo name='textmemo-b' text='' dbpath='module/textmemo-b'/>
</section>
<section name='section-b' text='' dbpath='module/section-b'>
<textmemo name='textmemo-c' text='' dbpath='module/textmemo-c'/>
<label name='label-c' text='A' dbpath='module/label-c'/>
<section name='section-c' text='' dbpath='module/section-c'>
<label name='label-d' text='A' dbpath='module/label-d'/>
</section>
</section>
</dform>
The element <section> works like a container for all kind of elements, itself included.
I need to translate this structure into objects: a List of elements (objects) that contains other List objects when the element is a Section. So I've created the following Interface and Classes:
public interface IWidget
{
String type { get;}
String name { get; set; }
String labelCation { get; set; }
String text { get; set; }
String dbpath { get; set; }
}
class Textmemo : IWidget
{
public String type { get; }
public String name { get; set; }
public String labelCation { get; set; }
public String text { get; set; }
public String dbpath { get; set; }
public List<IWidget> subsection { get; set; }
public Textmemo()
{
type = "CONTROL";
}
}
class Label : IWidget
{
public String type { get; }
public String name { get; set; }
public String labelCation { get; set; }
public String text { get; set; }
public String dbpath { get; set; }
public List<IWidget> subsection { get; set; }
public Label()
{
type = "LABEL";
}
}
class Section : IWidget
{
public String type { get; }
public String name { get; set; }
public String labelCation { get; set; }
public String text { get; set; }
public String dbpath { get; set; }
public List<IWidget> subsection { get; set; }
public Section()
{
type = "SECTION";
subsection = new List<IWidget>();
}
}
The Section class has one more property compared with the interface IWidget from which it inherits, that is the subsection property.
Then I was ready to move my steps starting from this example XmlSerializer serialize generic List of interface
but I really don't understand how to manage the <section> element in my code, that, at the moment, it is nothing more than the signature of the class:
public class WidgetsList: List<IWidget>, IXmlSerializable
{
public WidgetsList() : base() { }
public System.Xml.Schema.XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
}
public void WriteXml(XmlWriter writer)
{
}
}
Thanks a lot for the advice!
Why are you wanting to implement IXmlSerializable yourself? You can use various attributes to have the framework do this for you. For example, define a base class (given all your implementations are the same):
public abstract class Widget
{
[XmlIgnore]
public abstract string type { get;}
[XmlAttribute]
public string name { get; set; }
[XmlIgnore]
public string labelCation { get; set; }
[XmlAttribute]
public string text { get; set; }
[XmlAttribute]
public string dbpath { get; set; }
}
The attributes here specify that type and labelCation are ignored (as they don't exist in the XML). The rest are mapped to XML attributes (e.g. name='abc').
You can then create your three sub-types:
public class Textmemo : Widget
{
public override string type { get; } = "CONTROL";
}
public class Label : Widget
{
public override string type { get; } = "LABEL";
}
public class Section : Widget
{
public override string type { get; } = "SECTION";
[XmlElement("textmemo", Type=typeof(Textmemo))]
[XmlElement("label", Type=typeof(Label))]
[XmlElement("section", Type=typeof(Section))]
public List<Widget> subsection { get; } = new List<Widget>();
}
Section is the interesting one as it defines the types permitted as child elements with the relevant name mappings. Similarly to this, you'd then define the root element:
[XmlRoot("dform")]
public class DForm
{
[XmlElement("textmemo", Type=typeof(Textmemo))]
[XmlElement("label", Type=typeof(Label))]
[XmlElement("section", Type=typeof(Section))]
public List<Widget> Widgets { get; } = new List<Widget>();
}
You can see in this demo that your XML round-tripped through the serializer is the same, thus proving this works.
Below I wrote parser using Xml Linq that will work
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
new Widget(FILENAME);
}
}
public class Widget
{
public static Widget root = new Widget();
public String type { get; set; }
public String name { get; set; }
public String labelCation { get; set; }
public String text { get; set; }
public String dbpath { get; set; }
public List<Widget> subsection { get; set; }
public Widget() { }
public Widget(string filename)
{
XDocument doc = XDocument.Load(filename);
XElement root = doc.Root;
RecursiveParse(root, Widget.root);
}
public static void RecursiveParse(XElement xParent, Widget textParent)
{
foreach (XElement child in xParent.Elements())
{
string elementName = child.Name.LocalName;
switch (elementName)
{
case "label" :
textParent.name = (string)child.Attribute("name");
textParent.labelCation = (string)child.Attribute("text");
textParent.dbpath = (string)child.Attribute("dbpath");
break;
case "section" :
if (textParent.subsection == null) textParent.subsection = new List<Widget>();
Widget childSection = new Widget();
textParent.subsection.Add(childSection);
RecursiveParse(child, childSection);
break;
default :
textParent.text = (string)child.Attribute("text");
textParent.labelCation = elementName;
break;
}
}
}
}
}
I have XML:
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
<Cube time='2015-12-16'>
<Cube currency='USD' rate='1.0933'/>
<Cube currency='JPY' rate='133.18'/>
</Cube>
</Cube>
</gesmes:Envelope>
which I'm trying to deserialize with:
[XmlRoot("Envelope", Namespace = EcbNameSpace)]
public class EcbEnvelope
{
const string EcbNameSpace = "http://www.gesmes.org/xml/2002-08-01";
[XmlElement("Sender", Namespace = EcbNameSpace)]
public string EcbSender { get; set; }
[XmlElement("subject", Namespace = EcbNameSpace)]
public string EcbSubject { get; set; }
[XmlArray("Cube")]
[XmlArrayItem("Cube")]
public List<CubeRoot> CubeRootEl { get; set; }
public class CubeRoot
{
[XmlAttribute("time")]
public string Time { get; set; }
[XmlElement("Cube")]
public List<CubeItem> CubeItems { get; set; }
public class CubeItem
{
[XmlAttribute("rate")]
public string RateStr { get; set; }
[XmlIgnore]
public decimal Rate
{
get { return decimal.Parse(RateStr); }
}
[XmlAttribute("currency")]
public string Currency { get; set; }
}
}
}
However, it deserializes CubeRootEl as empty list. If I remove namspaces from XML, then it deserializes successfully. What am I doing wrong? I tried adding empty namespaces to CubeRootEl in code, but also unsuccessfully.
Here's the code used for deserialization:
var serializer = new XmlSerializer(typeof(EcbEnvelope));
using (var streamReader = new StreamReader(pathToFile))
var a = serializer.Deserialize(streamReader) as EcbEnvelope;
}
You have a few issues:
You do not specify a namespace for the property public List<CubeRoot> CubeRootEl. When a namespace for a property is not specified, XmlSerializer assumes it to be in the same namespace as the containing element, which would in this case be "http://www.gesmes.org/xml/2002-08-01". But the <Cube> elements are not in this namespace since they do not have the "gesmes:" prefix.
Your XML has a default namespace declaration xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref". Thus the <Cube> elements are actually in this namespace.
Sender is not a simple string-valued element, it has a nested element <gesmes:name>European Central Bank</gesmes:name>.
Fixing these three issues allows your XML to be deserialized:
[XmlRoot("Envelope", Namespace = GesmesNameSpace)]
public class EcbEnvelope
{
public const string GesmesNameSpace = "http://www.gesmes.org/xml/2002-08-01";
public const string EcbNameSpace = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";
[XmlElement("Sender", Namespace = GesmesNameSpace)]
public EcbSender Sender { get; set; }
[XmlElement("subject", Namespace = GesmesNameSpace)]
public string EcbSubject { get; set; }
[XmlArray("Cube", Namespace = EcbNameSpace)]
[XmlArrayItem("Cube")]
public List<CubeRoot> CubeRootEl { get; set; }
public class EcbSender
{
[XmlElement("name")]
public string Name { get; set; }
}
public class CubeRoot
{
[XmlAttribute("time")]
public string Time { get; set; }
[XmlElement("Cube")]
public List<CubeItem> CubeItems { get; set; }
public class CubeItem
{
[XmlAttribute("rate")]
public string RateStr { get; set; }
[XmlIgnore]
public decimal Rate
{
get { return decimal.Parse(RateStr); }
}
[XmlAttribute("currency")]
public string Currency { get; set; }
}
}
}
Given the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<userAttributeList>
<attribute>
<userId>12345678</userId>
<attId>1234</attId>
<attName>Group</attName>
<attTypeId>8</attTypeId>
<attTypeName>User Group</attTypeName>
<attData>Member</attData>
</attribute>
<attribute>
<userId>12345678</userId>
<attId>1235</attId>
<attName>Contact Name</attName>
<attTypeId>16</attTypeId>
<attTypeName>Contact Center Greeting</attTypeName>
<attData>John Smith</attData>
</attribute>
...
</userAttributeList>
I want to deserialize it into the following classes:
[Serializable]
[XmlTypeAttribute(AnonymousType = true)]
public class UserAttributeList
{
[XmlArray(ElementName = "userAttributeList")]
[XmlArrayItem(ElementName = "attribute")]
public List<UserAttribute> attributes { get; set; }
public UserAttributeList()
{
attributes = new List<UserAttribute>();
}
}
[Serializable]
public class UserAttribute
{
public String userId { get; set; }
public String attId { get; set; }
public String attName { get; set; }
public String attTypeId { get; set; }
public String attTypeName { get; set; }
public String attData { get; set; }
}
Using the code below, where GetResponseStream() returns the XML object listed above:
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "userAttributeList";
xRoot.IsNullable = true;
XmlSerializer serializer = new XmlSerializer(typeof(UserAttributeList), xRoot);
try
{
return (UserAttributeList)serializer.Deserialize(request.GetResponse().GetResponseStream());
}
catch (Exception exc)
{
return null;
}
My code compiles with no errors, but the UserAttributeList that is returned shows no child "attribute" items. No errors are thrown
I would sooner do something like:
public class userAttributeList
{
[XmlElement]
public List<UserAttribute> attribute { get; set; }
public UserAttributeList()
{
attribute = new List<UserAttribute>();
}
}
public class UserAttribute
{
public int userId { get; set; }
public int attId { get; set; }
public string attName { get; set; }
public int attTypeId { get; set; }
public string attTypeName { get; set; }
public string attData { get; set; }
}
Personally I'd use LinqToXsd. Take the existing xml, generate an xsd from it then use LinqToXsd to load that xml into a LinqToXsd object. Then you can do things like:
xml.company.com.reports.report.Load(xmlFileContents);
to build a POCO.