I have an XML file with many devices and many slots. I need to make lists of both. I am trying with the device type but it is always null.
<?xml version="1.0" encoding="UTF-8"?>
<DataFileSetup>
<System Name="Local">
<SysInfo>
<Software>
<VersionCreated>X3 SP5 (RELEASE-181228) (64-bit)</VersionCreated>
<VersionModifed>X3 SP5 (RELEASE-181228) (64-bit)</VersionModifed>
<License_Type>Professional</License_Type>
</Software>
</SysInfo>
<DewesoftSetup>
<Devices>
<StartStoreTime>43874.6969328704</StartStoreTime>
<SampleRate>50000</SampleRate>
<BlockSize>1000</BlockSize>
<IBRate>10</IBRate>
<AAFsr>21000</AAFsr>
<MaxSampling>200000</MaxSampling>
<Device Type="AI">
<Slot Index="0">
<MeasuredValue>VOLTAGE</MeasuredValue>
<Range>10 V</Range>
<LPFilter_Type>BU</LPFilter_Type>
<LPFilter_Hz>10000</LPFilter_Hz>
<LPFilter_Order>2</LPFilter_Order>
<HPFilter_Hz>1</HPFilter_Hz>
<OutMathChEnabled>8;1;0;0;0;0;0;0;0</OutMathChEnabled>
</Slot>
</Device>
<Device Type="DI">
....
</Device>
</Devices>
</DewesoftSetup>
</System>
</DataFileSetup>
public static void readXML()
{
string deviceType;
XmlReader reader = XmlReader.Create(DewesoftCard.xmlFileName);
reader.ReadToFollowing("DeviceName");
reader.Read();
deviceType = reader.Value;
reader.ReadToFollowing("DewesoftSetup");
if (deviceType == "SIRIUSi")
{
XmlSerializer serializer = new XmlSerializer(typeof(DewesoftSiriusDevices));
DewesoftSiriusDevices setupSirius = (DewesoftSiriusDevices)serializer.Deserialize(reader);
}
else if (deviceType == "KRYPTONi TH")
{
XmlSerializer serializer = new XmlSerializer(typeof(DewesoftKryptonDevices));
DewesoftKryptonDevices setupKrypton = (DewesoftKryptonDevices)serializer.Deserialize(reader);
}
}
[XmlRoot(ElementName = "DewesoftSetup")]
public class DewesoftSiriusDevices
{
[XmlElement(ElementName ="Devices")]
public DewesoftSiriusSetup dewesoftSiriusSetup { get; set; }
[XmlElement(ElementName = "Device")]
public List<DeviceType> deviceType { get; set; }
};
[XmlRoot(ElementName = "DewesoftSetup")]
public class DewesoftKryptonDevices
{
[XmlElement(ElementName = "Devices")]
public DewesoftKryptonSetup dewesoftKryptonSetup { get; set; }
[XmlElement(ElementName = "Device")]
public List<DeviceType> deviceType { get; set; }
};
public class DewesoftSiriusSetup
{
public double StartStoreTime;
public int SampleRate;
public int IBRate;
public int AAFsr;
public int MaxSampling;
};
public class DewesoftKryptonSetup
{
public double StartStoreTime;
public int SampleRate;
public int BlockSize;
public int IBRate;
public int MaxSampling;
};
public class DeviceType
{
[XmlAttribute(AttributeName = "Type")]
public string type;
};
The dewesoftSiriusSetup or dewesoftKryptonSetup is populated correctly.
Is there something I am missing from the code? Along with the device type, inside of there I also need the different slots as a list but I havent gotten that far since I feel like if I get the device figured out it will be the same for slots
Related
I need to deserialize xml file and its structured this way:
<NPCs>
<LabAssistant1>
<Questions>
<Question>
<Type>CheckBox</Type>
<Points>10</Points>
<Text>Q1</Text>
<Answers>
<Answer>
<Correct>False</Correct>
<Text>A1</Text>
</Answer>
<Answer>
<Correct>True</Correct>
<Text>A2</Text>
</Answer>
<Answer>
<Correct>False</Correct>
<Text>A3</Text>
</Answer>
</Answers>
</Question>
</Questions>
</LabAssistant1>
<LabAssistant2>
<Questions>
...
</Questions>
</LabAssistant2>
</NPCs>
So as you can see am having root node NPCs and my goal is to read questions separately by LabAssistant1 name or any tag name in NPCs.
String questionsPath = path+"/questions.xml";
XmlReader reader=XmlReader.Create(new StreamReader(questionsPath));
XmlRootAttribute xmlRoot = new XmlRootAttribute();
xmlRoot.ElementName = npc;
reader.ReadToDescendant(npc);
XmlSerializer se = new XmlSerializer(typeof(Question[]),xmlRoot);
Question[] qs=se.Deserialize(reader) as Question[];
Console.WriteLine(qs.Length.ToString()); // Always 0
Above code should output 2 objects of Question as array, but it doesn't
Here are the classes Question and Answer, anything is wrong with my attached attributes?
public class Question
{
[XmlElement(ElementName="Text")]
public String Text { get; set; }
[XmlArray(ElementName = "Answers")]
public Answer[] Answers { get; set; }
[XmlElement(ElementName = "Type")]
public QuestionType Type { get; set; }
[XmlElement(ElementName = "Points")]
public int Points { get; set; }
public Question()
{
}
public Question(String text, Answer[] answers, QuestionType type,int points)
{
this.Text = text;
this.Answers = answers;
this.Type = type;
this.Points = points;
}
}
public class Answer
{
[XmlElement(ElementName="Text")]
public String Text { get; set; }
[XmlElement(ElementName = "Correct")]
public bool Correct { get; set; }
public Answer()
{
}
public Answer(String text, bool correct)
{
this.Text = text;
this.Correct = correct;
}
}
You could use the UnknownElement event of XmlSerializer to load all the lab assistants into memory, like so:
public class LabAssistant
{
static XmlSerializer listSerializer;
static LabAssistant()
{
// This must be cached to prevent memory & resource leaks.
// See http://msdn.microsoft.com/en-us/library/System.Xml.Serialization.XmlSerializer%28v=vs.110%29.aspx
listSerializer = new XmlSerializer(typeof(List<Question>), new XmlRootAttribute("Questions"));
}
public List<Question> Questions { get; set; }
public static bool TryDeserializeFromXml(XmlElement element, out string name, out LabAssistant assistant)
{
name = element.Name;
var child = element.ChildNodes.OfType<XmlElement>().Where(el => el.Name == "Questions").FirstOrDefault();
if (child != null)
{
var list = child.OuterXml.LoadFromXML<List<Question>>(listSerializer);
if (list != null)
{
assistant = new LabAssistant() { Questions = list };
return true;
}
}
assistant = null;
return false;
}
}
public class NPCs
{
public NPCs()
{
this.LabAssistants = new Dictionary<string, LabAssistant>();
}
public static XmlSerializer CreateXmlSerializer()
{
// No need to cache this.
var serializer = new XmlSerializer(typeof(NPCs));
serializer.UnknownElement += new XmlElementEventHandler(NPCs.XmlSerializer_LoadLabAssistants);
return serializer;
}
[XmlIgnore]
public Dictionary<string, LabAssistant> LabAssistants { get; set; }
public static void XmlSerializer_LoadLabAssistants(object sender, XmlElementEventArgs e)
{
var obj = e.ObjectBeingDeserialized;
var element = e.Element;
if (obj is NPCs)
{
var npcs = (NPCs)obj;
string name;
LabAssistant assistant;
if (LabAssistant.TryDeserializeFromXml(element, out name, out assistant))
npcs.LabAssistants[name] = assistant;
}
}
}
Using the following helper methods:
public static class XmlSerializationHelper
{
public static T LoadFromXML<T>(this string xmlString)
{
return xmlString.LoadFromXML<T>(new XmlSerializer(typeof(T)));
}
public static T LoadFromXML<T>(this string xmlString, XmlSerializer serial)
{
T returnValue = default(T);
using (StringReader reader = new StringReader(xmlString))
{
object result = serial.Deserialize(reader);
if (result is T)
{
returnValue = (T)result;
}
}
return returnValue;
}
}
Having done this, you now have a dictionary of lab assistants by name.
While this code will deserialize your data correctly, it won't reserialize it. Custom code to serialize the dictionary would be required.
One final note - XmlSerializer will choke on the XML you provided because it requires that Boolean values be in lowercase. Thus the following will throw an exception:
<Correct>False</Correct>
If you did not mistype the XML and it really contains Booleans in this format, you will need to manually handle these fields.
I needed to create QuestionCollection class to hold the array of questions (having typeof(Question[]) throws <TagName xmlns="> was not expected, probably because the deserializer is not smart enough).
What i do next is first reading to tag LabAssistant or any tag name, next reading to its child Questions tag and after that i deserialize the questions into QuestionCollection, so with ReadToDescendant I can access any child elements of the NPCs
String questionsPath = Application.dataPath + "/Resources/questions.xml";
XmlReader reader=XmlReader.Create(new StreamReader(questionsPath));
reader.ReadToDescendant("LabAssistant");
reader.ReadToDescendant("Questions");
XmlSerializer se = new XmlSerializer(typeof(QuestionCollection));
QuestionCollection qc=(QuestionCollection)se.Deserialize(reader);
QuestionCollection class:
[XmlType("Questions")]
public class QuestionCollection
{
[XmlElement("Question")]
public Question[] Questions { get; set; }
public QuestionCollection() { }
}
Question class
[XmlType("Question")]
public class Question
{
[XmlElement("Text")]
public String Text { get; set; }
[XmlArray("Answers")]
public Answer[] Answers { get; set; }
[XmlElement("Type")]
public QuestionType Type { get; set; }
[XmlElement("Points")]
public int Points { get; set; }
public Question() { }
}
Answer class:
[XmlType("Answer")]
public class Answer
{
[XmlElement("Text")]
public String Text { get; set; }
[XmlElement("Correct")]
public bool Correct { get; set; }
public Answer() { }
}
Hi guys I have 2 classes like this:
[XmlRoot("Config")]
public class ConfigClass
{
[XmlElement("Configuration1")]
public string Config1 { get; set; }
[XmlArray("Infos")]
[XmlArrayItem("Info")]
public OtherInfo[] OtherInfos { get; set; }
}
public class OtherInfo
{
public string Info1 { get; set; }
public string Info2 { get; set; }
}
When I serialize the root class the XML result is like this:
<?xml version="1.0"?>
<Config>
<Configuration1>Text</Configuration1>
<Infos>
<Info>
<Info1>Test 2</Info1>
<Info2>Text 3</Info2>
</Info>
<Info>
<Info1>Test 4</Info1>
<Info2>Text 5</Info2>
</Info>
</Infos>
</Config>
But I would like the OtherInfo class was serialized as a single string like this:
<?xml version="1.0"?>
<Config>
<Configuration1>Text</Configuration1>
<Infos>
<Info>
Test 2:Text 3
</Info>
<Info>
Test 4:Text 5
</Info>
</Infos>
</Config>
How I can do that?
You can implement the IXmlSerializable interface, so the Info1 and Info2 properties are serialized the way <Info>Info1:Info2</Info>:
public class OtherInfo: IXmlSerializable
{
public string Info1 { get; set; }
public string Info2 { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
var content = reader.ReadElementContentAsString();
if (String.IsNullOrWhiteSpace(content))
return;
var infos = content.Split(':');
if (infos.Length < 2)
return;
this.Info1 = infos[0];
this.Info2 = infos[1];
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteString(String.Format("{0}:{1}", this.Info1, this.Info2));
}
}
If having those properties in the format "Info1:Info2" is also needed inside the application and not just for Xml serialization, then you could have a property in OtherInfo like the following and hide Info1 and Info2 from the serialization:
public class OtherInfo
{
[XmlIgnore]
public string Info1 { get; set; }
[XmlIgnore]
public string Info2 { get; set; }
[XmlText]
public string InfoString
{
get
{
return String.Format("{0}:{1}", this.Info1, this.Info2);
}
set
{
if (String.IsNullOrWhiteSpace(value))
return;
var infos = value.Split(':');
if (infos.Length < 2)
return;
this.Info1 = infos[0];
this.Info2 = infos[1];
}
}
}
The XML is generated and loaded by the same .NET with c# desktop application using XMLSerialize serialization / deserialization.
The serializable class structur is quiet complex, so I just made a selection of the two relevant classes.
Now, when I deserialize, everything is loaded except the Mapping Messages (or Messages as how the object list is called in the Organization.
Does anyone have an explanation for this behaviour?
Any tips or hints for improving what has already been made are also always appreciated.
Thank you.
I have the following XML:
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xsd="Company.Test3.Crm.Crm2Queue.Config.xsd">
<organizations>
<organization name="Vanilla">
<settings>
<ignoreemptyfields>true</ignoreemptyfields>
<throwerroronmissingconfiguration>true</throwerroronmissingconfiguration>
</settings>
<endpoints>
<endpoint>
<serviceUri>http://www.webservicex.net/usaddressverification.asmx</serviceUri>
</endpoint>
</endpoints>
<messages>
<message name="account">
<field name="accountnumber" mappedname="State" />
<field name="address1_county" mappedname="Zip" />
<field name="address1_latitude" mappedname="City" />
</message>
</messages>
<entities>
<entity name="account" messageschema="/XSD/.xsd" identifier="accountid">
<events>
<event name="create" message="" />
<event name="update" message="" />
<event name="delete" message="" />
</events>
</entity>
</entities>
</organization>
</organizations>
</configuration>
Now the serializable class looks as following:
[Serializable()]
public class Organization
{
#region XmlIgnore
[XmlIgnore()]
public string Id { get; set; }
[XmlIgnore()]
public bool Checked { get; set; }
[XmlIgnore()]
public List<MappingMessage> mappingMessages { get; set; }
#endregion
#region Attributes
[XmlAttribute("name")]
public string Name { get; set; }
#endregion
#region Properties
[XmlElement("settings")]
public Settings Settings { get; set; }
public bool ShouldSerializeSettings() { return (Settings != null && (Settings.IgnoreEmptyFields.HasValue || Settings.ThrowErrorOnMissingConfiguration.HasValue)); }
[XmlArray("endpoints")]
[XmlArrayItem("endpoint")]
public List<Endpoint> Endpoints { get; set; }
public bool ShouldSerializeignoreEndpoints() { return (Endpoints.Count > 0); }
[XmlArray("messages")]
[XmlArrayItem("message")]
public List<MappingMessage> Messages
{
get { return mappingMessages.Where(mm => (mm.Fields.Where(fi => !string.IsNullOrEmpty(fi.MappedName)).ToList().Count > 0)).ToList(); }
set { mappingMessages = value; }
}
public bool ShouldSerializeFilledMappingMessages() { return (mappingMessages.Where(mm => (mm.Fields.Where(fi => !string.IsNullOrEmpty(fi.MappedName)).ToList().Count > 0)).ToList().Count > 0); }
//public bool ShouldSerializeMappingMessages() { return (MappingMessages.Where(mm=> (mm.Fields.Where(fi=> !string.IsNullOrEmpty(fi.MappedName)).ToList().Count > 0)).ToList().Count > 0); }
[XmlArray("entities")]
[XmlArrayItem("entity")]
public List<Entity> Entities { get; set; }
public bool ShouldSerializeEntities() { return (Entities.Count > 0); }
#endregion
#region Constructors
public Organization()
{
Settings = new Settings();
Endpoints = new List<Endpoint>();
mappingMessages = new List<MappingMessage>();
Entities = new List<Entity>();
Checked = false;
}
public Organization(string name)
: this()
{
Name = name;
}
public Organization(string id, string name)
: this(name)
{
Id = id;
}
#endregion
}
[Serializable()]
public class MappingMessage
{
#region XmlIgnore
[XmlIgnore()]
public string EntityId { get; set; }
[XmlIgnore()]
public bool Checked { get; set; }
[XmlIgnore()]
public List<Field> Fields { get; set; }
#endregion
#region Attributes
[XmlAttribute("id")]
public string Id { get; set; }
[XmlAttribute("name")]
public string Name { get; set; }
#endregion
#region Properties
[XmlElement("field")]
public List<Field> SelectedFields
{
get
{
return Fields.Where(fi=> !string.IsNullOrEmpty(fi.MappedName)).ToList();
}
set
{
Fields = value;
}
}
public bool ShouldSerializeSelectedFields() { return (SelectedFields.Count > 0); }
[XmlElement("subentity")]
public List<SubEntity> SubEntities { get; set; }
public bool ShouldSerializeSubEntities() { return (SubEntities.Count > 0); }
[XmlElement("parententity")]
public List<ParentEntity> ParentEntities { get; set; }
public bool ShouldSerializeParentEntities() { return (ParentEntities.Count > 0); }
#endregion
#region Constructors
public MappingMessage()
{
Checked = false;
Fields = new List<Field>();
SubEntities = new List<SubEntity>();
ParentEntities = new List<ParentEntity>();
}
public MappingMessage(string entityId)
: this()
{
EntityId = entityId;
}
public MappingMessage(string entityId, string name)
: this(entityId)
{
Name = name;
}
#endregion
}
And I use deserialization as shown below:
foreach (ZipEntry zipEntry in zipFile)
{
using (MemoryStream memoryStream = new MemoryStream())
{
if (zipEntry.FileName.ToLower().EndsWith(".crm.crm2queue.config.xml"))
{
using (StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8))
{
zipEntry.Extract(memoryStream);
memoryStream.Position = 0;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Ciber.Crm.MappingCRMTo.Data.Configuration));
configuration = (Configuration)xmlSerializer.Deserialize(streamReader);
}
}
}
}
The deserializer tries to fill the list returnepublic List<MappingMessage> Messages. In order to the serializer invoke the setter, you must change the property type to an immutable collection type, say MappingMessage[].
Edit : to see that, you can replace the Entities auto-property by a property with backing field, and set a breakpoint in both getter and setter. You should not break in the setter, only in the getter.
I wanna serialize this class:
[Serializable]
[XmlRoot(ElementName = "Rates")]
public class CbrRate : IRate
{
public CbrRate()
{
}
public CbrRate(DateTime date, ICurrency currency, decimal rate)
{
Currency = currency;
Date = date;
Rate = rate;
}
[XmlIgnore]
public string SrcName
{
get { return "CBR"; }
}
[XmlElement(ElementName = "RequestDate")]
public DateTime Date { get; set; }
[XmlIgnore]
public ICurrency Currency { get; set; }
[XmlElement(ElementName = "Direction")]
public string Direction
{
get { return "RUR=>" + CodeChar.Trim(); }
}
[XmlElement(ElementName = "RateValue")]
public decimal Rate { get; set; }
[XmlElement(ElementName = "RateBase")]
public decimal BaseRate
{
get { return Math.Round(Rate/Nominal, 4); }
}
[XmlElement(ElementName = "RateCross")]
public decimal CrossRate
{
get { return Math.Round(1.00M/BaseRate, 4); }
}
[XmlElement(ElementName = "CodeNum")]
public int CodeNum
{
get { return Currency.CodeNumIso; }
}
[XmlElement(ElementName = "CodeISO")]
public string CodeChar
{
get { return Currency.CodeCharIso; }
}
[XmlElement(ElementName = "CurrencyName")]
public string Name
{
get { return Currency.Name; }
}
[XmlElement(ElementName = "Nominal")]
public decimal Nominal
{
get { return Currency.Nominal; }
}
}
public static XDocument Serialize<T>(this T source)
{
var target = new XDocument();
var s = new XmlSerializer(typeof (T));
using (var writer = target.CreateWriter())
{
s.Serialize(writer, source);
writer.Close();
}
return target;
}
But, that I have:
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfCbrRate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CbrRate>
<RequestDate>2011-09-05T18:49:55.1195696+04:00</RequestDate>
<RateValue>31.0539</RateValue>
</CbrRate>
...
How I can create correct xml, like this:
<ArrayOfRates>
<Rates>
<RequestDate></RequestDate>
<Direction></Direction>
<RateValue></RateValue>
<RateBase></RateBase>
...
First of all, .Net XmlSerializer will only serialize read/write properties (or fields). That's why only RequestDate and RateValue are serialized.
In order to achieve the XML structure you mentioned, you need to create a wrapper class as Roel said.
So, assuming you are serializing a List<CbrRate >, you will need to create a wrapper class for the list to have it serialized as you want it. Something like this:
[XmlRoot("root")]
public class ListOfRates
{
[XmlArray("ArrayOfRates")]
[XmlArrayItem("Rate")]
public List<CbrRate> Rates { get; set; }
}
this will produce the xml you want. Or you can play around with the attributes a little but if you don't want to have a root:
[XmlRoot("ArrayOfRates")]
public class ListOfRates
{
[XmlArrayItem("Rate")]
public List<CbrRate> Rates { get; set; }
}
the two attributes XmlArray and XmlArrayItem are key here. If you don't provide a name for the xml element, it will default to the property name.
Question: How does the class for the serialization of this XML content look ?
<?xml version="1.0" encoding="utf-8"?>
<vcc:CreateTextSearchResponse xmlns:vcc="urn:veloconnect:catalog-1.1" xmlns:vct="urn:veloconnect:transaction-1.0">
<vct:BuyersID>12345</vct:BuyersID>
<vct:ResponseCode>200</vct:ResponseCode>
<vct:TransactionID>225</vct:TransactionID>
<vct:StatusCode>2</vct:StatusCode>
<vct:IsTest>false</vct:IsTest>
<vcc:TotalCount>3876</vcc:TotalCount>
</vcc:CreateTextSearchResponse>
If I let it run through xsd.exe, it generates an error.
I have no problem generating this:
<?xml version="1.0" encoding="utf-8"?>
<CreateTextSearchResponse>
<BuyersID>15942</BuyersID>
<ResponseCode>200</ResponseCode>
<TransactionID>225</TransactionID>
<StatusCode>2</StatusCode>
<IsTest>false</IsTest>
<TotalCount>3876</TotalCount>
</CreateTextSearchResponse>
It's just that I need those namespaces to deserialize it (and later on reserialize), so I can't just leave it like this (it's needed by a 3rd party web-service)...
Like this:
[XmlRoot(Namespace = CreateTextSearchResponse.CatalogNamespace)]
public class CreateTextSearchResponse
{
public const string CatalogNamespace = "urn:veloconnect:catalog-1.1",
TransactionNamespace = "urn:veloconnect:transaction-1.0";
[XmlElement(Namespace=TransactionNamespace)]
public int BuyersId { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public int ResponseCode { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public int TransactionID { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public int StatusCode { get; set; }
[XmlElement(Namespace = TransactionNamespace)]
public bool IsTest { get; set; }
[XmlElement(Namespace = CatalogNamespace)]
public int TotalCount { get; set; }
}
public static void Main()
{
var ser = new XmlSerializer(typeof(CreateTextSearchResponse));
var obj = new CreateTextSearchResponse
{
BuyersId = 12345,
ResponseCode = 200,
TransactionID = 225,
StatusCode = 2,
IsTest = false,
TotalCount = 3876
};
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("vcc", CreateTextSearchResponse.CatalogNamespace);
ns.Add("vct", CreateTextSearchResponse.TransactionNamespace);
ser.Serialize(Console.Out, obj, ns);
}
unfortunately there are special characters in your namesapce that Xml can't handle