I'm trying to serialize object for import to another Software and the issue is, that elements in XML that is to be imported contain ":" (p.e.: < ftr:filter>).
I declared classes overriding those names with [XmlAttribute("ftr:filter")] and [XMLElement(ftr:differentFilter")], but serializer products different nodes. I bet it has something to do with encoding, but I'm not able to change the result (thought I changed encoding).
Example of classes:
public class ListPrijemkaRequest
{
[XmlAttribute("version")]
public string Version { get; set; }
[XmlAttribute("prijemkaVersion")]
public string PrijemkaVersion { get; set; }
[XmlElement("lst:requestPrijemka")]
public List<RequestPrijemka> Requests { get; set; }
}
public class RequestPrijemka
{
[XmlElement("ftr:filter")]
public RequestDateFilter Filter { get; set; }
}
Desired ooutput:
< lst:listPrijemkaRequest version="2.0" prijemkaVersion="2.0">
< lst:requestPrijemka>
< ftr:filter>
< ftr:dateFrom>2013-01-10</ftr:dateFrom>
< ftr:dateTill>2013-03-30</ftr:dateTill>
< /ftr:filter>
< /lst:requestPrijemka>
< /lst:listPrijemkaRequest>
Obtained output:
< lst_x003A_listPrijemkaRequest version="2.0" prijemkaVersion="2.0">
< lst_x003A_requestPrijemka>
< ftr_x003A_filter>
< ftr_x003A_dateFrom>2013-01-10</ftr_x003A_dateFrom>
< ftr_x003A_dateTill>2013-03-30</ftr_x003A_dateTill>
< /ftr_x003A_filter>
< /lst_x003A_requestPrijemka>
< /lst_x003A_listPrijemkaRequest>
If those "tags" ftr / lst are namespaces, there is no need to "hard-code" them, you can setup the serializer to use those namespaces.
http://msdn.microsoft.com/en-us/library/ms163161%28v=vs.110%29.aspx
Example (taken from XML Serialization and namespace prefixes)
[XmlRoot("Node", Namespace="http://your.companies.namespace")]
public class ListPrijemkaRequest {
[XmlElement("requestPrijemka")]
public List<RequestPrijemka> Requests { get; set; }
}
static class Program
{
static void Main()
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("lst", "http://your.companies.namespace");
XmlSerializer xser = new XmlSerializer(typeof(ListPrijemkaRequest));
xser.Serialize(Console.Out, new ListPrijemkaRequest(), ns);
}
}
If not, I don't think it's possible with "default" serialization.
Other options:
Use custom serialization (IXmlSerializable), see: http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly
Do post editing of the serialized file and do a string replace with the desired node names
But like I said in my comment, it is not recommended to use : in node names in the first place!
[XmlRoot("listPrijemkaRequest", Namespace = "http://your.companies.namespace/lst")]
public class ListPrijemkaRequest {
[XmlAttribute("version")]
public string Version { get; set; }
[XmlAttribute("prijemkaVersion")]
public string PrijemkaVersion { get; set; }
[XmlElement("requestPrijemka")]
public List<RequestPrijemka> Requests { get; set; }
}
public class RequestDateFilter
{
[XmlElement(ElementName = "dateFrom")]
public DateTime DateFrom { get; set; }
[XmlElement(ElementName = "dateTill")]
public DateTime DateTill { get; set; }
}
public class RequestPrijemka {
[XmlElement("filter", Namespace = "http://your.companies.namespace/ftr")]
public RequestDateFilter Filter { get; set; }
}
static class Program {
static void Main() {
var ns = new XmlSerializerNamespaces();
ns.Add("lst", "http://your.companies.namespace/lst");
ns.Add("ftr", "http://your.companies.namespace/ftr");
var xser = new XmlSerializer(typeof(ListPrijemkaRequest));
var obj = new ListPrijemkaRequest
{
Version = "2.0",
PrijemkaVersion = "2.0",
Requests = new List<RequestPrijemka>
{
new RequestPrijemka
{
Filter = new RequestDateFilter {DateFrom = DateTime.Now, DateTill = DateTime.Now}
}
}
};
xser.Serialize(Console.Out, obj, ns);
Console.ReadLine();
}
}
Produce this xml:
<?xml version="1.0" encoding="cp866"?>
<lst:listPrijemkaRequest xmlns:ftr="http://your.companies.namespace/ftr" version="2.0" prijemkaVersion="2.0" xmlns:lst="http://your.companies.namespace/lst">
<lst:requestPrijemka>
<ftr:filter>
<ftr:dateFrom>2014-07-17T16:17:47.0601039+03:00</ftr:dateFrom>
<ftr:dateTill>2014-07-17T16:17:47.061104+03:00</ftr:dateTill>
</ftr:filter>
</lst:requestPrijemka>
</lst:listPrijemkaRequest>
Looks similar with what you need.
Related
I have an XML file that I am parsing through and have come across a specific element that has it's own child nodes. The XML file is below:
<status.AppleSettings>
<AppleInstance MaxCost="250" Status="77" NewMode="5" SharePrice="350"
FlagTF="False" TimeClock="0" TimeClockSec="14"
Options="7532890" ID="JK_7755" Owner="SLP90"
Server="PA.SL90.COL" Name="SLP90" GroupName="COL.PA"
Instance="AppleServiceInstance" NewFlag="True" FinalCount="0"/>
<AppleInstance MaxCost="5" Status="0" NewMode="1" SharePrice="0"
FlagTF="False" TimeClock="300" TimeClockSec="1000"
Options="56794577431" Owner="A.CON" Instance="SL91"
NewFlag="True" FinalCount="1" List="1450, 1430"
Keyrepo="SYSTEMSERVER_7671902"/>
</status.AppleSettings>
As you can see, there's a parent node - AppleSettings and then two child nodes w/ the same name - AppleInstance. I created two separate classes for the child nodes since they have different attributes. I am able to access AppleSettings and when I do a quickwatch I can see the two child nodes inside, I just can't figure out how to access them. New to XML parsing and C# so everything is trial and error, learning a lot from stackoverflow.
Here is the code I have to access the AppleSettings parent node:
private List<Data> GetAppleSettingsNode(List<XmlDocument> XMLdocument, List<Data> DataList)
{
for (int i = 0; i < XMLdocument.Count(); i++)
{
AppleSettings temp = new AppleSettings();
var temp2 = XMLdocument[i].DocumentElement.SelectNodes("//AppleSettings");
foreach (var node in temp2)
{
var temp3 = node.ToString();
}
XmlNode xmlNode1 = XMLdocument[i].SelectSingleNode("//AppleSettings");
XmlSerializer serial1 = new XmlSerializer(typeof(AppleSettings));
temp = (AppleSettings)serial1.Deserialize(new XmlNodeReader(xmlNode1));
}
}
Is it even necessry to access the AppleSettings node? Could I go directly to the two AppleInstance child nodes? If someone could help me out, I'd appreciate it. Thanks!
It is better to use LINQ to XML API.
(1) The code below shows how to access any XML attribute by its name.
(2) .FirstOrDefault()?.Value technique will prevent exceptions generation when an attribute is missing.
c#
void Main()
{
const string FILENAME = #"e:\Temp\AppleSettings.xml";
XDocument doc = XDocument.Load(FILENAME);
foreach (var el in doc.Descendants("AppleInstance"))
{
Console.WriteLine("MaxCost={0}", el.Attributes("MaxCost").FirstOrDefault()?.Value);
Console.WriteLine("Instance={0}", el.Attributes("Instance").FirstOrDefault()?.Value);
Console.WriteLine("GroupName={0}", el.Attributes("GroupName").FirstOrDefault()?.Value);
}
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication8
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = (Root)serializer.Deserialize(reader);
}
}
public class Root
{
[XmlArray("status.AppleSettings")]
[XmlArrayItem("AppleInstance")]
public List<ApppleInstance> AppleInstances { get; set; }
}
public class ApppleInstance
{
[XmlAttribute()]
public int MaxCost { get; set; }
[XmlAttribute()]
public int Status { get; set; }
[XmlAttribute()]
public int NewMode { get; set; }
[XmlAttribute()]
public int SharePrice { get; set; }
private Boolean _FlagTF { get; set; }
[XmlAttribute()]
public string FlagTF
{
get { return _FlagTF? "True" : "False";}
set { _FlagTF = (value == "True") ? true : false;}
}
[XmlAttribute()]
public int TimeClock { get; set; }
[XmlAttribute()]
public int TimeClockSec { get; set; }
[XmlAttribute()]
public long Options { get; set; }
[XmlAttribute()]
public string ID { get; set; }
[XmlAttribute()]
public string Owner { get; set; }
[XmlAttribute()]
public string Server { get; set; }
[XmlAttribute()]
public string Name { get; set; }
[XmlAttribute()]
public string GroupName { get; set; }
[XmlAttribute()]
public string Instance { get; set; }
private Boolean _NewFlag { get; set; }
[XmlAttribute()]
public string NewFlag
{
get { return _NewFlag ? "True" : "False"; }
set { _NewFlag = (value == "True") ? true : false; }
}
[XmlAttribute()]
public int FinalCount { get; set; }
private int[] _List { get; set; }
[XmlAttribute()]
public string List
{
get { return string.Join(",",_List);}
set { _List = value.Split(new char[] {','}).Select(x => int.Parse(x)).ToArray() ;}
}
[XmlAttribute()]
public string Keyrepo { get; set; }
}
}
The i of LargeXMLResponse[i] is loop count of the Large XML response if your response tag in wrapped up in between, and if you have a alternative way please go ahead with.
var ResponseToList = LargeXMLResponse[i].Descendants("Response").ToList();
if (ResponseToList.Count() > 0){
for (var pf = 0; pf < ResponseToList.Count(); pf++)
{
ResponseInfoList.Add(new ResponseToList{
id = ResponseToList[pf].Descendants("Block").Attributes("id").Count() > 0 ?
ResponseToList[pf].Descendants("Block ").Attributes("id").First().Value : "",
});
}
}
I wrote a generic method for Object to XML string using XMLSerializer class.
Below is my class
public class SampleJson
{
public string fname { get; set; }
public string lname { get; set; }
public int age { get; set; }
public AdditionalInformation AdditionalInformation { get; set; }
}
public class AdditionalInformation
{
public string firstlane { get; set; }
public string secondlane { get; set; }
public decimal? cityCode { get; set; }
public int? countryCode { get; set; }
public bool? isValid { get; set; }
public DateTime enteredDate { get; set; }
}
And below is Generic Method
public class QAZ
{
public static string Foo<T>(T dataToSerialize)
{
var stringWriter = new StringWriter();
XmlTextWriter xmlTextWriter = null;
var serializer = new XmlSerializer(dataToSerialize.GetType());
xmlTextWriter = new XmlTextWriter(stringWriter);
serializer.Serialize(xmlTextWriter, dataToSerialize);
return stringWriter.ToString();
}
}
class Bar
{
static void Main(string[] args)
{
var sampleJson = typeof(SampleJson);
var fooMethod = typeof(QAZ).GetMethod("Foo");
var fooOfBarMethod = fooMethod.MakeGenericMethod(new[] {sampleJson});
string xml= fooOfBarMethod.Invoke(new QAZ(), new object[] {new SampleJson()}).ToString();
Console.ReadKey();
}
}
But I'm getting the output is
<?xml version="1.0" encoding="UTF-16"?>
-<SampleJson xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<age>0</age>
</SampleJson>
I don't understand why XmlSerializer serializes only int property.
Can anyone please tell me the issue that I'm doing.
The main agenda here is I want to generate an xsd for SampleJson class. In order to do that I am trying to convert the class to xml. From xml to xsd. Is there a way to generate xsd from a class?
I think this might help you to understand better, I wrote an example please do like or dislike if it has or hasn't helped.
public class Vehicle
{
public string VRM;
}
class Program
{
static void Main(string[] args)
{
var Reg = new Vehicle { VRM = "LP65 UGT" };
var writer = new System.Xml.Serialization.XmlSerializer(typeof(Vehicle));
var wfile = new System.IO.StreamWriter(#"C:\Myexample\NewVehicle.xml");
writer.Serialize(wfile, Reg);
wfile.Close();
Console.WriteLine("Vehicle Reg is now written in xml format ");
Console.ReadKey();
}
}
The above example will write successfully to XML file ensure you create the folder first on your C drive My example and then run the above to see the result for yourself and see if it can point you to the correct direction hopefully.
I see this question often enough, but nobody's title really seems to depict their question. I get a large response object back from a Web API that contains general response information, along with the data object I want to deserialize.
Full XML:
<?xml version="1.0"?>
<root>
<status>
<apiErrorCode>0</apiErrorCode>
<apiErrorMessage/>
<dbErrorCode>0</dbErrorCode>
<dbErrorMessage/>
<dbErrorList/>
</status>
<data>
<modelName>ReportXDTO</modelName>
<modelData>
<id>1780</id>
<reportTitle>Access Level (select) with Door Assignment</reportTitle>
<hasParameters>true</hasParameters>
<parameters>
<dataType>STRING</dataType>
<title>Access Level:</title>
<index>1</index>
<allowMulti>true</allowMulti>
<selectSql>SELECT DISTINCT [Name] FROM dbo.[Levels] WHERE [PrecisionFlag] = '0' ORDER BY [Name] </selectSql>
<values>
<value>Door 1</value>
<used>1</used>
</values>
<values>
<value>Door 2</value>
<used>1</used>
</values>
<values>
<value>Door 3</value>
<used>1</used>
</values>
</parameters>
<sourceSql>SELECT [Name], [SData] FROM [Schedules]</sourceSql>
<report/>
</modelData>
<itemReturned>1</itemReturned>
<itemTotal>1</itemTotal>
</data>
<listInfo>
<pageIdRequested>1</pageIdRequested>
<pageIdCurrent>1</pageIdCurrent>
<pageIdFirst>1</pageIdFirst>
<pageIdPrev>1</pageIdPrev>
<pageIdNext>1</pageIdNext>
<pageIdLast>1</pageIdLast>
<itemRequested>1</itemRequested>
<itemReturned>1</itemReturned>
<itemStart>1</itemStart>
<itemEnd>1</itemEnd>
<itemTotal>1</itemTotal>
</listInfo>
</root>
I only want to deserialize the modelData element. The modelData object type is dynamic, depending on the API call.
I deserialize xml in other applications, and created the following method, but don't know how to specifically ONLY get the modelData element:
public static T ConvertXmltoClass<T>(HttpResponseMessage http, string elementName) where T : new()
{
var newClass = new T();
try
{
var doc = JsonConvert.DeserializeXmlNode(http.Content.ReadAsStringAsync().Result, "root");
XmlReader reader = new XmlNodeReader(doc);
reader.ReadToFollowing(elementName);
//The xml needs to show the proper object name
var xml = reader.ReadOuterXml().Replace(elementName, newClass.GetType().Name);
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
var serializer = new XmlSerializer(typeof(T));
newClass = (T)serializer.Deserialize(stream);
}
}
catch (Exception e)
{
AppLog.LogException(System.Reflection.MethodBase.GetCurrentMethod().Name, e);
}
return newClass;
}
I have updated this thread multiple times now, to stay current. I started updating it with the first solution. But that solution by itself didn't solve the problem. With the code how it is right now, I get no exceptions, but don't get the xml deserialized to my object. Instead I get a new, blank object. Thoughts?
THOUGH the object type can change, here is my current object I am dealing with: (PLEASE NOTE, that I deserialize the exact xml in modelData, in the Web API)
namespace WebApiCommon.DataObjects
{
[Serializable]
public class ReportXDto
{
public ReportXDto()
{
Parameters = new List<ReportParameterXDto>();
}
public int Id { get; set; }
public string ReportTitle { get; set; }
public bool HasParameters { get; set; } = false;
public List<ReportParameterXDto> Parameters { get; set; }
public string SourceSql { get; set; }
public DataTable Report { get; set; }
}
[Serializable]
public class ReportXDto
{
public ReportXDto()
{
Parameters = new List<ReportParameterXDto>();
}
public int Id { get; set; }
public string ReportTitle { get; set; }
public bool HasParameters { get; set; } = false;
public List<ReportParameterXDto> Parameters { get; set; }
public string SourceSql { get; set; }
public DataTable Report { get; set; }
}
[Serializable]
public class ReportParameterValuesXDto
{
public string Value { get; set; } = "";
public bool Used { get; set; } = false;
}
}
Firstly, XmlSerializer is case sensitive. Thus your property names need to match the XML element names exactly -- unless overridden with an attribute that controls XML serialization such as [XmlElement(ElementName="id")]. To generate a data model with the correct casing I used http://xmltocsharp.azurewebsites.net/ which resulted in:
public class ReportParameterValuesXDto
{
[XmlElement(ElementName="value")]
public string Value { get; set; }
[XmlElement(ElementName="used")]
public string Used { get; set; }
}
public class ReportParametersXDto
{
[XmlElement(ElementName="dataType")]
public string DataType { get; set; }
[XmlElement(ElementName="title")]
public string Title { get; set; }
[XmlElement(ElementName="index")]
public string Index { get; set; }
[XmlElement(ElementName="allowMulti")]
public string AllowMulti { get; set; }
[XmlElement(ElementName="selectSql")]
public string SelectSql { get; set; }
[XmlElement(ElementName="values")]
public List<ReportParameterValuesXDto> Values { get; set; }
}
public class ReportXDto
{
[XmlElement(ElementName="id")]
public string Id { get; set; }
[XmlElement(ElementName="reportTitle")]
public string ReportTitle { get; set; }
[XmlElement(ElementName="hasParameters")]
public string HasParameters { get; set; }
[XmlElement(ElementName="parameters")]
public ReportParametersXDto Parameters { get; set; }
[XmlElement(ElementName="sourceSql")]
public string SourceSql { get; set; }
[XmlElement(ElementName="report")]
public string Report { get; set; }
}
(After generating the model, I modified the class names to match your naming convention.)
Given the correct data model, you can deserialize directly from a selected XmlNode using an XmlNodeReader as shown in How to deserialize a node in a large document using XmlSerializer without having to re-serialize to an intermediate XML string. The following extension method does the trick:
public static partial class XmlExtensions
{
public static IEnumerable<T> DeserializeElements<T>(this XmlNode root, string localName, string namespaceUri)
{
return new XmlNodeReader(root).DeserializeElements<T>(localName, namespaceUri);
}
public static IEnumerable<T> DeserializeElements<T>(this XmlReader reader, string localName, string namespaceUri)
{
var serializer = XmlSerializerFactory.Create(typeof(T), localName, namespaceUri);
while (!reader.EOF)
{
if (!(reader.NodeType == XmlNodeType.Element && reader.LocalName == localName && reader.NamespaceURI == namespaceUri))
reader.ReadToFollowing(localName, namespaceUri);
if (!reader.EOF)
{
yield return (T)serializer.Deserialize(reader);
// Note that the serializer will advance the reader past the end of the node
}
}
}
}
public static class XmlSerializerFactory
{
// To avoid a memory leak the serializer must be cached.
// https://stackoverflow.com/questions/23897145/memory-leak-using-streamreader-and-xmlserializer
// This factory taken from
// https://stackoverflow.com/questions/34128757/wrap-properties-with-cdata-section-xml-serialization-c-sharp/34138648#34138648
readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache;
readonly static object padlock;
static XmlSerializerFactory()
{
padlock = new object();
cache = new Dictionary<Tuple<Type, string, string>, XmlSerializer>();
}
public static XmlSerializer Create(Type serializedType, string rootName, string rootNamespace)
{
if (serializedType == null)
throw new ArgumentNullException();
if (rootName == null && rootNamespace == null)
return new XmlSerializer(serializedType);
lock (padlock)
{
XmlSerializer serializer;
var key = Tuple.Create(serializedType, rootName, rootNamespace);
if (!cache.TryGetValue(key, out serializer))
cache[key] = serializer = new XmlSerializer(serializedType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
return serializer;
}
}
}
Then you would deserialize as follows:
var modelData = doc.DeserializeElements<ReportXDto>("modelData", "").FirstOrDefault();
Working sample .Net fiddle here.
For Huge xml files always use XmlReader so you do not get an out of memory issue. See code below to get the element as a string :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
//or Create(Stream)
XmlReader reader = XmlReader.Create(FILENAME);
reader.ReadToFollowing("modelData");
if (!reader.EOF)
{
string modelDataStr = reader.ReadOuterXml();
}
}
}
}
Im developing a web api in C#. The web api should return an xml like:
<personDatas>
<personData>
<affdatalist>
<object1> information </object1>
<object2> information </object2>
<object3> information </object3>
</affdatalist>
<anotherObject1> infooo </anotherObject1>
<anotherObject2> infooo </anotherObject2>
</personData>
</personDatas>
The xml can have 1 to many personData elements and the personData element can have 1 to many affdatalist elements.
What would be the best practice to generate such an XML in a web api using C# 6?
Ive tried with XSD based on a schema definition.
Any help would be greatly appreciated.
You can use the Serialize method to generate this xml from the model it self.
public string SerializeXml<T>(T config)
{
XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
string xml = "";
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = false;
using (var sww = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sww, settings))
{
xsSubmit.Serialize(writer, config);
xml = sww.ToString();
}
}
return xml;
}
This will return XML string , you need the model which is similar to your required XML.
This is what i have created as model from your XML that you can change as per your requiment.
[XmlRoot(ElementName = "affdatalist")]
public class Affdatalist
{
[XmlElement(ElementName = "object1")]
public string Object1 { get; set; }
[XmlElement(ElementName = "object2")]
public string Object2 { get; set; }
[XmlElement(ElementName = "object3")]
public string Object3 { get; set; }
}
[XmlRoot(ElementName = "personData")]
public class PersonData
{
[XmlElement(ElementName = "affdatalist")]
public Affdatalist Affdatalist { get; set; }
[XmlElement(ElementName = "anotherObject1")]
public string AnotherObject1 { get; set; }
[XmlElement(ElementName = "anotherObject2")]
public string AnotherObject2 { get; set; }
}
[XmlRoot(ElementName = "personDatas")]
public class PersonDatas
{
[XmlElement(ElementName = "personData")]
public PersonData PersonData { get; set; }
}
You can use as sample below
PersonDatas data = new PersonDatas();
var xml = this.SerializeXml<PersonDatas>(data); // your model with data
This is my sample after using what Sulay Shah said:
PersonDatas data = new PersonDatas();
for (int x = 0; x < 2; x++)
{
data.PersonData = new PersonData();
for (int i = 0; i < 2; i++)
{
Affdatalist affdata = new Affdatalist();
affdata.Object1 = "LALALALALLALA";
affdata.Object2 = "lqlqlqlqlqlqlql";
affdata.Object3 = "ililililililililililil";
data.PersonData.Affdatalist.Add(affdata);
}
data.PersonData.AnotherObject1 = "ali";
data.PersonData.AnotherObject2 = "Nazar";
data.personDataList.Add(data.PersonData);
}
var xml = this.SerializeXml<PersonDatas>(data);
return xml;
The above generated below
xml:<?xml version="1.0" encoding="utf-16"?>
<personDatas xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<personData>
<affdatalist>
<object1>LALALALALLALA</object1>
<object2>lqlqlqlqlqlqlql</object2>
<object3>ililililililililililil</object3>
</affdatalist>
<affdatalist>
<object1>LALALALALLALA</object1>
<object2>lqlqlqlqlqlqlql</object2>
<object3>ililililililililililil</object3>
</affdatalist>
<anotherObject1>ali</anotherObject1>
<anotherObject2>Nazar</anotherObject2>
</personData>
<personData>
<affdatalist>
<object1>LALALALALLALA</object1>
<object2>lqlqlqlqlqlqlql</object2>
<object3>ililililililililililil</object3>
</affdatalist>
<affdatalist>
<object1>LALALALALLALA</object1>
<object2>lqlqlqlqlqlqlql</object2>
<object3>ililililililililililil</object3>
</affdatalist>
<anotherObject1>ali</anotherObject1>
<anotherObject2>Nazar</anotherObject2>
</personData>
<PersonData>
<affdatalist>
<object1>LALALALALLALA</object1>
<object2>lqlqlqlqlqlqlql</object2>
<object3>ililililililililililil</object3>
</affdatalist>
<affdatalist>
<object1>LALALALALLALA</object1>
<object2>lqlqlqlqlqlqlql</object2>
<object3>ililililililililililil</object3>
</affdatalist>
<anotherObject1>ali</anotherObject1>
<anotherObject2>Nazar</anotherObject2>
</PersonData>
</personDatas>
If you want c# classes like this
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace namespace
{
public class AffData {
public string Property1 { get; set; }
}
public class AnotherObject1 {
public string Property1 { get; set; }
}
public class AnotherObject2 {
public string Property1 { get; set; }
}
public class PersonData {
public List<AffData> AffDataList { get; set; }
public AnotherObject1 AnotherObject1 { get; set; }
public AnotherObject2 AnotherObject2 { get; set; }
}
The below xml will work if you serialize List
<ArrayOfPersonData>
<PersonData>
<ArrayOfAffData>
<AffData>
<Property1>info</Property1>
</AffData>
<AffData> <Property1>info</Property1></AffData>
<AffData> <Property1>info</Property1> </AffData>
</ArrayOfAffData>
<anotherObject1> <Property1>info</Property1> </anotherObject1>
<anotherObject2> <Property1>info</Property1> </anotherObject2>
</PersonData>
</ArrayOfPersonData>
public static string ConvertToXml(object payload, string rootElement, bool addPrefixSuffix)
{
string json = JsonConvert.SerializeObject(payload);
string elementName = "DummyRoot";
if (addPrefixSuffix)
{
string prefix = "{" + elementName + ":";
string postfix = "}";
json = string.Concat(prefix, json, postfix);
}
var payloadXml = JsonConvert.DeserializeXNode(json, rootElement)?.ToString();
if (addPrefixSuffix)
{
payloadXml = payloadXml.ToString().Replace("<" + elementName + ">", string.Empty);
payloadXml = payloadXml.ToString().Replace("</" + elementName + ">", string.Empty);
}
return Regex.Replace(payloadXml, #"\s+", String.Empty);
}
Use the above function like ConvertToXml(requeststring, "", false)... Here second parameter empty will returns your expected result.
I have the follow XML structure:
<Document>
<Sectors>
<Sector>
SectorName1
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector>
SectorName2
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Also I have classes for deserialize:
public class MetaDataXML
{
public class SectorXML
{
[XmlArrayItem(ElementName = "Sector")]
string SectorName { get; set; }
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
public List<SectorXML> Sectors { get; set; }
}
And part of code which do deserialize:
var xRoot = new XmlRootAttribute { ElementName = "Document", IsNullable = true };
var reader = new XmlSerializer(typeof(MetaDataXML), xRoot);
var data = (MetaDataXML)reader.Deserialize(streamXML);
After deserialization I successfully get subsectors velues, but I didn't get values for SectorName. How I need to organize my structure of class that I'll get values "SectorName1" and "SectorName2" for my string SectorName property?
I found that that this case it's a "Mixed Content". How we can parse this text values?
Whilst I am not entirely sure what it is you're trying to achieve here, I've made a few modifications to your XML class and provided some sample code below that is able to retrieve all of the information about a sector, including its name and the name of all the subsectors inside it.
XML Class:
namespace DocumentXml
{
[XmlRoot("Document")]
public class Document
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlAttribute("SectorName")]
public string SectorName { get; set; }
[XmlArray("Subsectors")]
[XmlArrayItem("Subsector")]
public string[] Subsectors { get; set; }
}
}
Main Program Class:
namespace DocumentXml
{
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
var serializer = new XmlSerializer(typeof(Document));
var document = serializer.Deserialize(File.OpenRead(path)) as Document;
var sectors = document.Sectors;
foreach (var s in sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}
Sample XML:
<Document>
<Sectors>
<Sector SectorName="SectorName1">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector SectorName="SectorName2">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Output:
EDIT
Since the XML structure cannot be changed, this new class will preserve the structure and also allow you to get the value in question. XmlText returns everything inside the value so a custom set had to be used to ensure that the whitespace was correctly trimmed from it.
[XmlRoot("Document")]
public class MetaDataXml
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlIgnore]
private string _sectorName;
[XmlText]
public string SectorName
{
get
{
return _sectorName;
}
set
{
_sectorName = value.Trim();
}
}
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
Sample Program:
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
using (var stream = File.OpenRead(path))
{
var deserializer = new XmlSerializer(typeof(MetaDataXml));
var data = (MetaDataXml)deserializer.Deserialize(stream);
foreach (var s in data.Sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
}
Console.ReadKey();
}
}