I've got another problem (which might not be an issue in terms of coding problems) but more of principle..been bugging me for a while. I have this c# class, as follows:
namespace SMCProcessMonitor
{
public class Config
{
[XmlElement("Recipient")]
public string recipient;
[XmlElement("Server-port")]
public int serverport;
[XmlElement("Username")]
public string username;
[XmlElement("Password")]
public string password;
[XmlElement("Program")]
public List<Programs> mPrograms = new List<Programs>();
[Serializable]
[XmlRoot("Email-Config")]
public class Email
{
public string Recipient
{
get
{
return SMCProcessMonitor.ConfigManager.mConfigurations.recipient;
}
set
{
SMCProcessMonitor.ConfigManager.mConfigurations.recipient = value;
}
}
public int ServerPort
{
get
{
return SMCProcessMonitor.ConfigManager.mConfigurations.serverport;
}
set
{
SMCProcessMonitor.ConfigManager.mConfigurations.serverport = value;
}
}
public string Username
{
get
{
return SMCProcessMonitor.ConfigManager.mConfigurations.username;
}
set
{
SMCProcessMonitor.ConfigManager.mConfigurations.username = value;
}
}
public string Password { get; set; }
}
}
I can serialize this almost fine. (i recently changed simple get; set; to the full-works as seen above, but when serialising i get something like this;
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Recipient>sd</Recipient>
<Server-port>1234</Server-port>
<Username>dk</Username>
<Password>kdkdk</Password>
</Config>
Basically I want to wrap these 4 tags in an "email-settings" tag.
Add the Serializable() and XmlRoot attributes up to the base class:
[Serializable()]
[XmlRoot("Email-Settings")]
public class Config
There are attributes to control aspects of xml serialization like this, see Controlling XML Serialization Using Attributes.
I think the one you want specifically is XmlRootAttribute.
You'll need to create an EmailSettings class that contains those 4 properties, and then make an instance of the EmailSettings class a member of your Config class.
Related
I am receiving back from a Web Service XML that looks like this:
<RESULT>
<GRP ID="INP">
<FLD NAME="SORDNO" TYPE="Char"></FLD>
<FLD NAME="SITENO" TYPE="Char">999</FLD>
</GRP>
<TAB DIM="100" ID="POS" SIZE="0"/>
<TAB DIM="500" ID="ERR" SIZE="2">
<LIN NUM="1">
<FLD NAME="ERRORS" TYPE="Char"/>
</LIN>
<LIN NUM="2">
<FLD NAME="ERRORS" TYPE="Char">Site code 999 is not valid</FLD>
</LIN>
</TAB>
I want to codify the XML into an object so I created a class that seems to match the XML structure:
namespace DropShipmentFulfillment.SagePOCreateProcess
{
public class SagePOCreateResponse1
{
[XmlRoot("RESULT")]
public class RESULT
{
[XmlElement("GRP")]
public RESULTGRP GRP;
[XmlElement("TAB")]
public RESULTTAB[] TAB;
}
public partial class RESULTGRP
{
[XmlAttribute("ID")]
public string ID;
[XmlElement("FLD")]
public RESULTFLD[] FLD;
}
public partial class RESULTTAB
{
[XmlAttribute("DIM")]
public string DIM;
[XmlAttribute("ID")]
public string ID;
[XmlAttribute("SIZE")]
public string SIZE;
[XmlElement("LIN")]
public RESULTLIN[] LIN;
}
public partial class RESULTLIN
{
[XmlAttribute("NUM")]
public string NUM;
[XmlElement("FLD")]
public RESULTFLD FLD;
}
public partial class RESULTFLD
{
[XmlAttribute("NAME")]
public string NAME;
[XmlAttribute("TYPE")]
public string TYPE;
}
}
}
When I perform the serialization I execute this code:
private SagePOCreateResponse1.RESULT GetPOResponse(SageWeb.CAdxResultXml sageSvcResponse)
{
string xml = sageSvcResponse.resultXml;
XmlSerializer serializer = new XmlSerializer(typeof(SagePOCreateResponse1.RESULT));
StringReader rdr = new StringReader(xml);
SagePOCreateResponse1.RESULT resultingMessage = (SagePOCreateResponse1.RESULT)serializer.Deserialize(rdr);
return resultingMessage;
}
When I execute the program I do not get an error indicating that the class structure does not match the XML structure, but specifically, the FLD element does not contain a value. For example, if I stop to take a look at a specific field (FLD), in GRP I get the attributes values but not the value of the element:
?objectResponse.GRP.FLD[0]
{DropShipmentFulfillment.SagePOCreateProcess.SagePOCreateResponse1.RESULTFLD}
NAME: "SORDNO"
TYPE: "Char"
It seems like the serializer is not putting the element value in place though I think I have named it right and I get no errors.
What am I missing? Why would it resolve the attributes and not the element values?
I did try doing the XSD creation to C# Class route, but when I had to deal with dynamic lines (LIN) I tried creating my own class.
Thanks to jdweng I was able to find a solution. Keeping all things the same from my question I changed one class:
public partial class RESULTFLD
{
[XmlAttribute("NAME")]
public string NAME;
[XmlAttribute("TYPE")]
public string TYPE;
[System.Xml.Serialization.XmlTextAttribute()]
public string Value;
}
I needed this line "[System.Xml.Serialization.XmlTextAttribute()]" instead of just the "[XmlText]" line.
The class now deserilizes the XML so I get both attribute values and innerText values.
I'm sure I am missing something very obvious, and I've read different threads (like this one, this and also this, just to name the last ones) but I still cannot find the answer...
Here are my classes:
using System;
using Newtonsoft.Json;
namespace WebAPIClient
{
public class XWTournament
{
private string name;
[JsonProperty("name")]
public string Name { get => name; set => name = value; }
}
public class Root
{
public XWTournament xwtournam { get => xwtournam; set => xwtournam = value; }
}
}
And here I try to use them:
msg = "{\"tournament\": {\"Name\": \"Worlds 2014 Flight One\"}}";
Root root = JsonConvert.DeserializeObject<Root>(msg) ;
string pippo = root.xwtournam.Name;
But in this case I am receiving a stack overflow error...
What am I missing? How can I read the variables in the string?
Edit: thanks to the useful answers, I have corrected the code in this way
using System;
using Newtonsoft.Json;
namespace WebAPIClient
{
public class XWTournament
{
//I've deleted the private variable
public string Name { get; set; }
}
public class Root
{
[JsonProperty("tournament")]
public XWTournament xwtournam { get; set; }
}
}
None of your classes have a property named tournament. Your JSON does. What does that suggest?
public class Root
{
public XWTournament tournament { get; set; }
}
You also don't need the infinite recursion in the setter as you wrote it. Try assigning to it: The getter and the setter both just call themselves. That's the cause of the stack overflow exception. You'd get one if you tried to set that property, too.
I want to deserialize XML to object in C#, object has one string property and list of other objects.
There are classes which describe XML object, my code doesn't work (it is below, XML is at end of my post). My Deserialize code doesn't return any object.
I think I do something wrong with attributes, could you check it and give me some advice to fix it.
Thanks for your help.
[XmlRoot("shepherd")]
public class Shepherd
{
[XmlElement("name")]
public string Name { get; set; }
[XmlArray(ElementName = "sheeps", IsNullable = true)]
[XmlArrayItem(ElementName = "sheep")]
public List<Sheep> Sheeps { get; set; }
}
public class Sheep
{
[XmlElement("colour")]
public string colour { get; set; }
}
There is C# code to deserialize XML to objects
var rootNode = new XmlRootAttribute();
rootNode.ElementName = "createShepherdRequest";
rootNode.Namespace = "http://www.sheeps.pl/webapi/1_0";
rootNode.IsNullable = true;
Type deserializeType = typeof(Shepherd[]);
var serializer = new XmlSerializer(deserializeType, rootNode);
using (Stream xmlStream = new MemoryStream())
{
doc.Save(xmlStream);
var result = serializer.Deserialize(xmlStream);
return result as Shepherd[];
}
There is XML example which I want to deserialize
<?xml version="1.0" encoding="utf-8"?>
<createShepherdRequest xmlns="http://www.sheeps.pl/webapi/1_0">
<shepherd>
<name>name1</name>
<sheeps>
<sheep>
<colour>colour1</colour>
</sheep>
<sheep>
<colour>colour2</colour>
</sheep>
<sheep>
<colour>colour3</colour>
</sheep>
</sheeps>
</shepherd>
</createShepherdRequest>
XmlRootAttribute does not change the name of the tag when used as an item. The serializer expects <Shepherd>, but finds <shepherd> instead. (XmlAttributeOverrides does not seem to work on arrays either.) One way to to fix it, is by changing the case of the class-name itself:
public class shepherd
{
// ...
}
An easier alternative to juggling with attributes, is to create a proper wrapper class:
[XmlRoot("createShepherdRequest", Namespace = "http://www.sheeps.pl/webapi/1_0")]
public class CreateShepherdRequest
{
[XmlElement("shepherd")]
public Shepherd Shepherd { get; set; }
}
I'm getting empty lists when I deserialize one of my List that has been concerted to XML.
I start out with my object GJurisdictions and serialize it to XML
<open511 xml:lang="en" xml:base="http://api.open511.info/" version="v0">
<jurisdictions>
<jurisdiction>
<id>my.id</id>
<languages>
<language>en</language>
</languages>
</jurisdiction>
</jurisdictions>
</open511>
This is exactly what I want but when I try to read it back in Languages is empty.
public class Jurisdiction
{
[XmlElement("id")]
[JsonProperty("id")]
public string Id { get; set; }
[XmlArray("languages")]
[XmlArrayItem("language")]
[JsonProperty("languages")]
public List<String> Languages { get; set; }
}
[XmlRoot("open511")]
public class JurisdictionsBase : Open511Base
{
private List<Jurisdiction> _jurisdictions;
[XmlArray("jurisdictions")]
[XmlArrayItem("jurisdiction")]
[JsonProperty("jurisdiction")]
public List<Jurisdiction> Jurisdictions
{
get { return _jurisdictions ?? (_jurisdictions = new List<Jurisdiction>()); }
set { _jurisdictions = value; }
}
}
The list of jurisdictions serializes perfectly and all the other properties (I edited for clarity) serialize perfectly but the language list is always empty, why?
Specification: http://open511.org/jurisdiction.html
Full Code: https://github.com/doublej42/Open511DotNet/blob/master/Open511DotNet/Jurisdiction.cs
So I didn't give enough information without reading the full source code. My problem was that somewhere else in my project I used some sample code from http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.readxml(v=vs.110).aspx
public void ReadXml (XmlReader reader)
{
personName = reader.ReadString();
}
Do not use the above code
it doesn't move the reader ahead correctly.
As mentioned here http://msdn.microsoft.com/query/dev12.query?appId=Dev12IDEF1&l=EN-US&k=k(System.Xml.XmlReader.ReadString);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.1);k(DevLang-csharp)&rd=true
public void ReadXml(System.Xml.XmlReader reader)
{
_unit = reader.ReadElementContentAsString();
}
Im serializing my class to XML. I have an issue with the root element of one of my classes is NOT being named properly.
The complete XML structure should look like the following.
<Workflow>
<Name>My Workflow</Name>
<Description />
<Modules>
<Module Name="Intro" MenuText="IntroText" />
</Modules>
</Workflow>
However Im getting this result
<Workflow>
<Name>My Workflow</Name>
<Description />
<Modules>
<WorkflowModule Name="Intro" MenuText="IntroText" />
</Modules>
</Workflow>
I want the element "WorkflowModule" to be called "Module" however the problem is that I already have another class called Module. So to get around this problem I called it a WorkflowModule and put a class XmlRoot() declartion like so;
[XmlRoot("Module")]
public class WorkflowModule
{...}
But when I serialize the Workflow class it still comes up with WorkflowModule.
Here are my 2 classes classes;
[XmlRoot("Workflow")]
public class Workflow
{
private string _name;
private string _description;
private List<WorkflowModule> _modules = new List<WorkflowModule>();
[XmlElement("Name")]
public String Name
{
get { }
set { }
}
[XmlElement("Description")]
public String Description
{
get { }
set { }
}
[XmlArrayItem(typeof(WorkflowModule))]
public List<WorkflowModule> Modules
{
get { }
set { }
}
}
[XmlRoot("Module")]
public class WorkflowModule
{
private string _name;
private string _menu_text;
public WorkflowModule()
{
}
[XmlAttribute("Name")]
public String Name
{
get { }
set { }
}
[XmlAttribute("MenuText")]
public String MenuText
{
get { }
set { }
}
}
}
Set the element name within XmlArrayItem attrubute:
[XmlArrayItem(typeof(WorkflowModule), ElementName = "Module")]
There are many ways to control it as defined in this duplicate post How do I Set XmlArrayItem Element name for a List<Custom> implementation?
These attribute control serialize from the this object's perspective as it transverses nested objects
[XmlArray("RootArrayElementNameGoesHere")]
[XmlArrayItem(typeof(Workflow), ElementName="ArrayItemElementNameGoesHere")]
public List<WorkflowModule> Modules
This attribute redefining the element name but can be overwritten with the local [XmlArrayItem] or [XmlElement] attributes to provides local override from the owning objects serialization
[XmlType(TypeName = "UseThisElementNameInsteadOfClassName")]
public class WorkflowModule
This attribute is only honored when its the direct object being serialized
[XmlRoot("UseThisElementNameWhenItIsTheRoot")]
public class WorkflowModule