I want to convert a c# class to an xml file without declaring default values in it. If I declare values on every propery in the class I got it to work and the XML has all the properties in it. The primarydata is my class with properties in it.
var pD = new PrimaryData();
XmlSerializer serializerPrimaryData = new XmlSerializer(typeof(PrimaryData));
serializerPrimaryData.Serialize(File.Create(xmlLocation), pD,ns);
But I dont want to declare any values.
If i run this code I get just:
<?xml version="1.0"?>
<PrimaryData />
I don't get the properties in the class as you can see. So how can I get the properties in the class without declaring them to a default value?
Any suggestions?
I have followed this guide: https://codehandbook.org/c-object-xml/
But he is declaring default values to his class.
public class PrimaryData
{
public PrimaryData();
public string BatchId { get; set; }
public CurrentOperation CurrentOperation { get; set; }
public Heat Heat { get; set; }
public string MaterialId { get; set; }
public List<Operation> Operations { get; set; }
public OrderInfo OrderInfo { get; set; }
public Plate Plate { get; set; }
}
Just set default values.
public class Employee
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
}
public static void Main(string[] args)
{
var employee = new Employee();
var sw = new StringWriter();
var se = new XmlSerializer(employee.GetType());
var tw = new XmlTextWriter(sw);
se.Serialize(tw, employee);
Console.WriteLine(sw.ToString());
Console.Read();
}
Result
<?xml version="1.0" encoding="utf-16"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FirstName />
<LastName />
</Employee>
Second solution is to set XmlElement(IsNullable = true)
public class Employee
{
[XmlElement(IsNullable = true)]
public string FirstName { get; set; }
[XmlElement(IsNullable = true)]
public string LastName { get; set; }
}
I have no clue what you are trying to do ...
XML serialization just makes a mirror of the object in different structure (aka XML - object will be represented by structured text).
If your class has no properties, nothing will be serialized to XML but only the base empty object.
My suggestion is to make a class with Dictionary<string, object> as property. Then you will be able to write into the Dictionary and serialize it.
But, it has some drawbacks. XML Serialization (if I remember correctly) does not support Dictionaries, so I would go with DataContract instead.
That might work :)
[DataContract]
public class PrimaryData
{
[DataMember(Name = "Data", Order = 0, IsRequired = true)]
public Dictionary<string, object> Data { get; set; }
}
You should add this annotation to your properties:
[XmlElement(IsNullable = true)]
public string Prop { get; set; }
The result in your xml should be something like this:
<Prop xsi:nil="true" />
Related
I am trying to Deserialize a xml file of this type
<?xml version="1.0" encoding="UTF-8"?>
<Network>
<ROUTES>
<ROUTE ID="RT_BALA_GLNC_R_162_154_1" DIRECTION="LEFT" ZONE="Richmond_Hill">
<ENTRANCESIGNAL>BALA_GLNC_G162</ENTRANCESIGNAL>
<EXITSIGNAL>BALA_DONS_G154</EXITSIGNAL>
<POINTENDIDS>
<POINTENDID POS="N">PT_BALA_GLNC_W11.TrackPortionConnection</POINTENDID>
<POINTENDID POS="N">PT_BALA_GLNC_W23.TrackPortionConnection</POINTENDID>
</POINTENDIDS>
</ROUTE>
<ROUTE ID="RT_BALA_ORLS_R_111_119_1" DIRECTION="RIGHT" ZONE="Richmond_Hill">
<ENTRANCESIGNAL>BALA_ORLS_G111</ENTRANCESIGNAL>
<EXITSIGNAL>BALA_ORLN_G119</EXITSIGNAL>
<POINTENDIDS>
<POINTENDID POS="N">PT_BALA_ORLS_W1.TrackPortionConnection</POINTENDID>
</POINTENDIDS>
</ROUTE>
<ROUTE ID="RT_BALA_GLNC_R_162D_154_1" DIRECTION="LEFT" ZONE="Richmond_Hill">
<ENTRANCESIGNAL>BALA_GLNC_G162D</ENTRANCESIGNAL>
<EXITSIGNAL>BALA_DONS_G154</EXITSIGNAL>
<POINTENDIDS>
<POINTENDID POS="R">PT_BALA_GLNC_W11.TrackPortionConnection</POINTENDID>
<POINTENDID POS="N">PT_BALA_GLNC_W23.TrackPortionConnection</POINTENDID>
</POINTENDIDS>
</ROUTE>
</ROUTES>
</Network>
I have tried this
class Program
{
static void Main(string[] args)
{
XmlSerializer deserializer = new XmlSerializer(typeof(Network));
TextReader reader = new StreamReader(#"xml File Location");
object obj = deserializer.Deserialize(reader);
Network XmlData = (Network)obj;
reader.Close();
Console.ReadLine();
}
}
[XmlRoot("Network")]
public class Network
{
[XmlElement("ROUTES")]
public List<ROUTE> ROUTES { get; set; }
}
public class ROUTE
{
[XmlAttribute("ID")]
public string ID { get; set; }
[XmlAttribute("DIRECTION")]
public string DIRECTION { get; set; }
[XmlElement("ENTRANCESIGNAL")]
public string ENTRANCESIGNAL { get; set; }
[XmlElement("EXITSIGNAL")]
public string EXITSIGNAL { get; set; }
[XmlElement("POINTENDIDS")]
public POINTENDIDS POINTENDIDS { get; set; }
}
public class POINTENDIDS
{
[XmlElement("POINTENDID")]
public List<POINTENDID> POINTENDID { get; set; }
}
public class POINTENDID
{
[XmlAttribute("POS")]
public string POS { get; set; }
}
I am doing it in a console application,
I started Debugging and put breakpoint on Network XmlData = (Network)obj;
I've got only 1 ROUTES and the values of "ID", "DIRECTION", "ENTRANCESIGNAL" ...etc are set to Null
being beginner in c# programming , I don't really understand what should I do !
Need help for this implementation
Fix you Network Class. The names in square brackets are case sensitive. You also need to add the Xml array attributes.
[XmlRoot("Network")]
public class Network
{
[XmlArrayItem("ROUTE")]
[XmlArray("ROUTES")]
public List<ROUTE> ROUTES { get; set; }
}
using System.Xml; //XmlDoc
using System.Xml.Linq;//XElement
using System.IO;//Path,File,Directory, Stream
Read and parse xml file:
XmlDocument XmlDoc = new XmlDocument();
XmlDoc.Load(XmlFilePath);
Another approach is using XElement instead:
XElement a = XElement.Load(#"c:\path\file");
Most often I prefer XElement over XmlDocument, but that's personal
If you are starting with C#, you'd need a book, and a simpler project. Streams and Xml are syntactically complex. Also, console apps are ugly, and Forms apps are not that hard to do with the graphical tools of VisualStudio.
Your C# classes are not exactly aligned with the XML file and the serializer returns only a partial result. What you can do instead if the XML structure is fixed is outlined here.
https://stackoverflow.com/a/17315863/99804
This then works as you want it to.
You will get the following auto-generated code.
Note: I have cleaned up the output to use auto-properties etc.
using System;
using System.Xml.Serialization;
// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks />
[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class Network
{
/// <remarks />
[XmlArrayItem("ROUTE", IsNullable = false)]
public NetworkROUTE[] ROUTES { get; set; }
}
[Serializable]
[XmlType(AnonymousType = true)]
public class NetworkROUTE
{
[XmlAttribute]
public string DIRECTION { get; set; }
public string ENTRANCESIGNAL { get; set; }
public string EXITSIGNAL { get; set; }
[XmlAttribute]
public string ID { get; set; }
[XmlArrayItem("POINTENDID", IsNullable = false)]
public NetworkROUTEPOINTENDID[] POINTENDIDS { get; set; }
[XmlAttribute]
public string ZONE { get; set; }
}
[Serializable]
[XmlType(AnonymousType = true)]
public class NetworkROUTEPOINTENDID
{
[XmlAttribute]
public string POS { get; set; }
[XmlText]
public string Value { get; set; }
}
i have part of xml document
<Tender SubTenderType="BC" TenderType="Check">
<TenderTotal>
<Amount>10.00</Amount>
</TenderTotal>
</Tender>
i need convert it to class.
public class Tender
{
public string SubTenderType { get; set; }
public string TenderType { get; set; }
public decimal Amount { get; set; }
}
what i already wrote and this work. but i interseing can i deserialize xml to class as written above?
[Serializable]
public class Tender
{
[XmlAttribute("SubTenderType")]
public string SubTenderType { get; set; }
[XmlAttribute("TenderType")]
public string TenderType { get; set; }
[XmlElement("TenderTotal")]
public TenderTotal TenderTotal { get; set; }
}
[Serializable]
public class TenderTotal
{
[XmlElement("Amount")]
public decimal Amount { get; set; }
}
You can deserialize xml to first Type "Tender" and next use autoMapper to map your type (create new object of different type)
create map:
config.CreateMap<TenderFirst, TenderSecond>().ForMember(x => x.TenderTotal.Amount, y => y.Amount ())
Having the following class without XmlAttribute:
public class Tender
{
public string SubTenderType { get; set; }
public string TenderType { get; set; }
public decimal Amount { get; set; }
}
You can use the XmlAttributeOverrides class to override the behavior of the serializer in such a way that instead of elements it would do the attributes.
var attrSTT = new XmlAttributes { XmlAttribute = new XmlAttributeAttribute("SubTenderType") };
var attrTT = new XmlAttributes { XmlAttribute = new XmlAttributeAttribute("TenderType") };
var overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Tender), nameof(Tender.SubTenderType), attrSTT);
overrides.Add(typeof(Tender), nameof(Tender.TenderType), attrTT);
var xs = new XmlSerializer(typeof(Tender), overrides);
However, in this way impossible add a new item or wrap one element in another.
Therefore, you have to do custom serialization, or map one type to another, or writing a custom xml reader/writer, or perform the read/write manually (for example, using linq2xml). There are many ways...
I am having issues creating the schema below...
<DocumentProperties>
<Document>
<Properties>
<propertyName>CNumber</propertyName>
<propertyValue>00645007803</propertyValue>
</Properties>
<targetFolder>\12345678\00645007803\</targetFolder>
</Document>
<Document>
<Properties>
<propertyName>CNumber</propertyName>
<propertyValue>00645007804</propertyValue>
</Properties>
<targetFolder>\12345678\00645007804\</targetFolder>
</Document>
</DocumentProperties>
I created the following classes to do this
public class DocumentProperties
{
public DocumentProperties()
{
Document = new List<Document>();
}
public List<Document> Document { get; set; }
}
public class Document
{
public Document()
{
Properties = new List<Properties>();
}
public List<Properties> Properties { get; set; }
public string targetFolder { get; set; }
}
public class Properties
{
public string propertyName { get; set; }
public string propertyValue { get; set; }
}
public class RetrieveMultipleDocumentsRequest
{
public SystemProperty SystemProperty { get; set; }
public RequestProperty RequestProperty { get; set; }
public DocumentProperties DocumentProperties { get; set; }
}
The output I am getting is "Document" and "Properties" twice as a parent child of each other. How do I resolve this?
Output from my classes
<DocumentProperties>
<Document>
<Document>
<Properties>
<Properties>
<propertyName>DizzzyGelespe</propertyName>
<propertyValue>8E077A60</propertyValue>
</Properties>
<Properties />
</Properties>
<targetFolder>C:\BXml\TargetFolder\</targetFolder>
</Document>
</Document>
</DocumentProperties>
Code that is generating the output:
public string Serialize(RetrieveMultipleDocumentsRequest details)
{
XmlSerializer serializer = new XmlSerializer(typeof(RetrieveMultipleDocumentsRequest));
using(StringWriter textWriter = new StringWriter())
{
serializer.Serialize(textWriter, details);
return textWriter.ToString();
}
}
You will need to annotate your object model as shown below in order to change the default serialization behavior. This application of the XmlElement attribute will prevent emiting out the parent tag based upon the encountered property and instead only emit out the containing data.
public class DocumentProperties
{
public DocumentProperties()
{
Document = new List<Document>();
}
[XmlElement("Document")]
public List<Document> Document { get; set; }
}
public class Document
{
public Document()
{
Properties = new List<Properties>();
}
[XmlElement("Properties")]
public List<Properties> Properties { get; set; }
public string targetFolder { get; set; }
}
Apparently your naming convention confused the XML serializer a bit. Just explicitly decorate the elements as below and it should work fine:
public class DocumentProperties
{
public DocumentProperties()
{
Document = new List<Document>();
}
[XmlElement("Document")]
public List<Document> Document { get; set; }
}
public class Document
{
public Document()
{
Properties = new List<Properties>();
}
[XmlElement("Properties")]
public List<Properties> Properties { get; set; }
public string targetFolder { get; set; }
}
Your problem here is with naming.
A list of documents should be called "documents" not "document", same goes for properties.
If you make these naming changes then you will see that your XML output is correct and makes sense.
I have an auto generated xml file with the following format.
<?xml version="1.0"?>
<School>
<Classes numberOfFields="5">
<Class name="10" dataType="double">
<Section value="A"/>
<Section value="B"/>
<Section value="C"/>
</Class>
<Class dataType="double"/>
<Class dataType="double"/>
<Class dataType="double"/>
<Class dataType="double"/>
</Classes>
</School>
I deserialize using "XmlDeserializer" as follows
School schoolResult = (School)xmlSerializer.Deserialize(stream);
XmlRootElement contains a collection of "Class" under "Classes" tag and further each "Class" would contain Collection of "Section".
And in C#, I have declared like this to deserialize "Classes" into a List of classes.
[XmlArray("Classes")]
[XmlArrayItem("Class", typeof(Class))]
public List<Class> Classes {};
Now to further deserialize Class into List of Sections, I have added the code as below.
[XmlArray("Class")]
[XmlArrayItem(ElementName="Section")]
public List<Section> ClassSections {};
My problem is I couldn't get the List of Sections values properly. Because I have "Class" as a class name in the first part and in second part I have mentioned same "Class" as Array element. So could any one tell how can I properly Deserialize my "School" object using "XmlSerializer" to get all the values properly.
Note: I cannot have a Array root tag like "Sections" under "Class". Because my xml document is auto generated. I cannot specify my own format.
Thanks...
try this :
public class School
{
[XmlAttribute]
public int numberOfFields { get; set; }
[XmlArray("Classes")]
[XmlArrayItem("Class", typeof(Class))]
public List<Class> Classes { get; set; }
}
public class Class
{
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string dataType { get; set; }
[XmlElement("Section")]
public List<Section> ClassSections { get; set; }
}
public class Section
{
[XmlAttribute]
public string value { get; set; }
}
* EDIT #1 **
--------------- Update Structure due to NumberOfFields is not readed ----------------
in my opinion it's not correct structure, but when u said it's an auto generated XML file, i think it simplest way to read it.
public class School
{
[XmlElement("Classes")]
public List<ArrayClass> Classes { get; set; }
}
public class ArrayClass
{
[XmlAttribute]
public int numberOfFields { get; set; }
[XmlElement("Class")]
public List<Class> Class { get; set; }
}
static void Main(string[] args)
{
var xml ="<?xml version=\"1.0\"?><School><Classes numberOfFields=\"5\"><Class name=\"10\" dataType=\"double\"><Section value=\"A\"/><Section value=\"B\"/><Section value=\"C\"/></Class><Class dataType=\"double\"/><Class dataType=\"double\"/><Class dataType=\"double\"/><Class dataType=\"double\"/></Classes></School>";
School result;
var serializer = new XmlSerializer(typeof(School));
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
using (var reader = new XmlNodeReader(xmlDoc))
{
result = (School)serializer.Deserialize(reader);
}
}
public class School
{
[XmlArray("Classes")]
[XmlArrayItem("Class")]
public List<Class> Classes { get; set; }
}
public class Class
{
[XmlElement("Section")]
public List<Section> ClassSections { get; set; }
}
public class Section
{
[XmlAttribute("value")]
public string Value { get; set; }
}
I have the following class:
[Serializable]
public class SomeModel
{
[XmlElement("SomeStringElementName")]
public string SomeString { get; set; }
[XmlElement("SomeInfoElementName")]
public int SomeInfo { get; set; }
}
Which (when populated with some test data) and Serialized using XmlSerializer.Serialize() results in the following XML:
<SomeModel>
<SomeStringElementName>testData</SomeStringElementName>
<SomeInfoElementName>5</SomeInfoElementName>
</SomeModel>
What I need to have is:
<SomeModel>
<SomeStringElementName Value="testData" />
<SomeInfoElementName Value="5" />
</SomeModel>
Is there a way to specify this as attributes without writing my own custom serialization code?
You will need wrapper classes:
public class SomeIntInfo
{
[XmlAttribute]
public int Value { get; set; }
}
public class SomeStringInfo
{
[XmlAttribute]
public string Value { get; set; }
}
public class SomeModel
{
[XmlElement("SomeStringElementName")]
public SomeStringInfo SomeString { get; set; }
[XmlElement("SomeInfoElementName")]
public SomeIntInfo SomeInfo { get; set; }
}
or a more generic approach if you prefer:
public class SomeInfo<T>
{
[XmlAttribute]
public T Value { get; set; }
}
public class SomeModel
{
[XmlElement("SomeStringElementName")]
public SomeInfo<string> SomeString { get; set; }
[XmlElement("SomeInfoElementName")]
public SomeInfo<int> SomeInfo { get; set; }
}
And then:
class Program
{
static void Main()
{
var model = new SomeModel
{
SomeString = new SomeInfo<string> { Value = "testData" },
SomeInfo = new SomeInfo<int> { Value = 5 }
};
var serializer = new XmlSerializer(model.GetType());
serializer.Serialize(Console.Out, model);
}
}
will produce:
<?xml version="1.0" encoding="ibm850"?>
<SomeModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SomeStringElementName Value="testData" />
<SomeInfoElementName Value="5" />
</SomeModel>
Kind of, use the XmlAttribute instead of XmlElement, but it won't look like what you want. It will look like the following:
<SomeModel SomeStringElementName="testData">
</SomeModel>
The only way I can think of to achieve what you want (natively) would be to have properties pointing to objects named SomeStringElementName and SomeInfoElementName where the class contained a single getter named "value". You could take this one step further and use DataContractSerializer so that the wrapper classes can be private. XmlSerializer won't read private properties.
// TODO: make the class generic so that an int or string can be used.
[Serializable]
public class SerializationClass
{
public SerializationClass(string value)
{
this.Value = value;
}
[XmlAttribute("value")]
public string Value { get; }
}
[Serializable]
public class SomeModel
{
[XmlIgnore]
public string SomeString { get; set; }
[XmlIgnore]
public int SomeInfo { get; set; }
[XmlElement]
public SerializationClass SomeStringElementName
{
get { return new SerializationClass(this.SomeString); }
}
}