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.
Related
My Deserializer executes without exception, but the resulting object is coming up with nulls. The source XML clearly shows values that for some reason are not being set in the target object. I can't for the life of me figure out why?
Source XML:
<soapenv:Fault xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>soapenv:Client</faultcode>
<faultstring>Could not insert new row - duplicate value in a UNIQUE INDEX column (Unique Index:).</faultstring>
<detail>
<axlError>
<axlcode>-239</axlcode>
<axlmessage>Could not insert new row - duplicate value in a UNIQUE INDEX column (Unique Index:).</axlmessage>
<request>addRoutePartition</request>
</axlError>
</detail>
Class:
using System.Xml.Serialization;
namespace AXLClassLibrary
{
[XmlRoot(ElementName = "Fault", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Fault
{
[XmlElement(ElementName = "faultcode")]
public string Faultcode { get; set; }
[XmlElement(ElementName = "faultstring")]
public string Faultstring { get; set; }
[XmlElement(ElementName = "detail")]
public Detail Detail { get; set; }
[XmlAttribute(AttributeName = "soapenv", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Soapenv { get; set; }
}
[XmlRoot(ElementName = "axlError")]
public class AxlError
{
[XmlElement(ElementName = "axlcode")]
public string Axlcode { get; set; }
[XmlElement(ElementName = "axlmessage")]
public string Axlmessage { get; set; }
[XmlElement(ElementName = "request")]
public string Request { get; set; }
}
[XmlRoot(ElementName = "detail")]
public class Detail
{
[XmlElement(ElementName = "axlError")]
public AxlError AxlError { get; set; }
}
}
Deserializer Code:
var resp = new StreamReader(ex.Response.GetResponseStream()).ReadToEnd();
XDocument xd = XDocument.Parse(resp);
XNamespace ns1 = "http://schemas.xmlsoap.org/soap/envelope/";
XNode faultXML = xd.Descendants(ns1 + "Fault").DescendantNodesAndSelf().First();
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "Fault";
xRoot.Namespace = "http://schemas.xmlsoap.org/soap/envelope/";
xRoot.IsNullable = false;
resp = faultXML.ToString();
Fault currentFault;
XmlSerializer serializer = new XmlSerializer(typeof(Fault), xRoot);
using (TextReader readFault = new StringReader(resp))
{
currentFault = (Fault)serializer.Deserialize(readFault);
}
I am trying to deserialize a string to object. Is xml node like syntax, but is not an xml (as there is no root node or namespace). This is what I have so far, having this error:
<delivery xmlns=''>. was not expected
Deserialize code:
var number = 2;
var amount = 3;
var xmlCommand = $"<delivery number=\"{number}\" amount=\"{amount}\" />";
XmlSerializer serializer = new XmlSerializer(typeof(Delivery));
var rdr = new StringReader(xmlCommand);
Delivery delivery = (Delivery)serializer.Deserialize(rdr);
Delivery object:
using System.Xml.Serialization;
namespace SOMWClient.Events
{
public class Delivery
{
[XmlAttribute(AttributeName = "number")]
public int Number { get; set; }
[XmlAttribute(AttributeName = "amount")]
public string Amount { get; set; }
public Delivery()
{
}
}
}
How can I avoid the xmlns error when deserializing ?
Change the Delivery class and add information about the root element (XmlRoot attribute):
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[XmlRoot("delivery")]
public class Delivery
{
[XmlAttribute(AttributeName = "number")]
public int Number { get; set; }
[XmlAttribute(AttributeName = "amount")]
public string Amount { get; set; }
public Delivery()
{ }
}
Add the root yourself like this:
XmlRootAttribute root = new XmlRootAttribute();
root.ElementName = "delivery";
// root.Namespace = "http://www.whatever.com";
root.IsNullable = true;
// your code goes below
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.
I have this existing XML file serving as a template with NO data, just simple nodes... here's a sample:
<?xml version="1.0" encoding="utf-8" ?>
<catalog>
<cd>
<title />
<artist />
<country />
<company />
<price />
<year />
</cd>
</catalog>
Now I have created a similar class for it.
public class Cd
{
public string Title { get; set; }
public string Artist { get; set; }
public string Country { get; set; }
public string Company { get; set; }
public string Price { get; set; }
public string Year { get; set; }
}
The purpose is this:
Put values on the properties of the var cd = new Cd(); object
Get the existing XML file (template) then pass the values in it (like mapping the object to the existing XML)
Transform the XML template(with values) into XSLT to become HTML
I think that's all.
How to properly do this?
Thanks a lot!
You can use serialization to achieve (1) and (2)
[Serializable]
public class Cd
{
public string Title { get; set; }
public string Artist { get; set; }
public string Country { get; set; }
public string Company { get; set; }
public string Price { get; set; }
public string Year { get; set; }
}
now in order to create an xml from an object use:
public static string SerializeObject<T>(this T obj)
{
var ms = new MemoryStream();
var xs = new XmlSerializer(obj.GetType());
var xmlTextWriter = new XmlTextWriter(ms, Encoding.UTF8);
xs.Serialize(xmlTextWriter, obj);
string serializedObject = new UTF8Encoding().GetString((((MemoryStream)xmlTextWriter.BaseStream).ToArray()));
return serializedObject;
}
in order to create an object from XML use:
public static T DeserializeObject<T>(this string xml)
{
if (xml == null)
throw new ArgumentNullException("xml");
var xs = new XmlSerializer(typeof(T));
var ms = new MemoryStream(new UTF8Encoding().GetBytes(xml));
try
{
new XmlTextWriter(ms, Encoding.UTF8);
return (T)xs.Deserialize(ms);
}
catch
{
return default(T);
}
finally
{
ms.Close();
}
}
I would create class:
class catalog
{
public CD cd {get;set;}
}
Here is serialization and deserealization helper:
public class Xml
{
public static string Serialize<T>(T value) where T : class
{
if (value == null)
{
return string.Empty;
}
var xmlSerializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(stringWriter))
{
xmlSerializer.Serialize(xmlWriter, value);
return stringWriter.ToString();
}
}
public static T Deserialize<T>(string xml)
{
var serializer = new XmlSerializer(typeof(T));
T result;
using (TextReader reader = new StringReader(xml))
{
result = (T) serializer.Deserialize(reader);
}
return result;
}
}
Simply call:
catalog catalogObject = Xml.Deserialize<catalog>(xmlCatalogString);
I suspect you also will need to put some attributes on properties like XmlElement(ElementName = "title") because it is case sensitive.
MSDN
I'm trying to deserialize an xml document:
<?xml version="1.0"?>
<games xmlns = "http://serialize">
<game>
<name>TEST1</name>
<code>TESTGAME1</code>
<ugn>1111111</ugn>
<bets>
<bet>5,00</bet>
</bets>
</game>
<game>
<name>TEST2</name>
<code>TESTGAME2</code>
<ugn>222222</ugn>
<bets>
<bet>0,30</bet>
<bet>0,90</bet>
</bets>
</game>
</games>
.cs class:
namespace XmlParse
{
using System.Collections.Generic;
using System.Runtime.Serialization;
[DataContract(Namespace = "http://serialize")]
public class game
{
#region Public Properties
[DataMember]
public string name { get; set; }
[DataMember]
public string code { get; set; }
[DataMember]
public long ugn { get; set; }
[DataMember]
public List<decimal> bets { get; set; }
#endregion
}
[KnownType(typeof(game))]
[DataContract(Namespace = "http://serialize")]
public class games
{
#region Public Properties
[DataMember]
public List<game> game { get; set; }
#endregion
}
}
Main:
FileStream fs = new FileStream(Path.Combine(this.path, xmlDocumentName), FileMode.Open);
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
DataContractSerializer ser = new DataContractSerializer(typeof(games));
// Deserialize the data and read it from the instance.
games deserializedPerson = (games)ser.ReadObject(reader, true);
reader.Close();
fs.Close();
deserializedPerson shows count = 0
what gives?
I figured it out. Maybe there are other implementations but this works. For the life of me I couldn't find any examples that use List inside an object. Here is a working example:
XML document to parse:
<?xml version="1.0"?>
<games xmlns = "http://serialize">
<game>
<name>TEST1</name>
<code>TESTGAME1</code>
<ugn>1111111</ugn>
<bets>
<bet>5,00</bet>
</bets>
</game>
<game>
<name>TEST2</name>
<code>TESTGAME2</code>
<ugn>222222</ugn>
<bets>
<bet>0,30</bet>
<bet>0,90</bet>
</bets>
</game>
</games>
.cs class:
namespace XmlParse
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
[DataContract(Name = "game", Namespace = "")]
public class Game
{
[DataMember(Name = "name", Order = 0)]
public string Name { get; private set; }
[DataMember(Name = "code", Order = 1)]
public string Code { get; private set; }
[DataMember(Name = "ugn", Order = 2)]
public string Ugn { get; private set; }
[DataMember(Name = "bets", Order = 3)]
public Bets Bets { get; private set; }
}
[CollectionDataContract(Name = "bets", ItemName = "bet", Namespace = "")]
public class Bets : List<string>
{
public List<decimal> BetList
{
get
{
return ConvertAll(y => decimal.Parse(y, NumberStyles.Currency));
}
}
}
[CollectionDataContract(Name = "games", Namespace = "")]
public class Games : List<Game>
{
}
}
Read and parse xml document:
string fileName = Path.Combine(this.path, "Document.xml");
DataContractSerializer dcs = new DataContractSerializer(typeof(Games));
FileStream fs = new FileStream(fileName, FileMode.Open);
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
Games games = (Games)dcs.ReadObject(reader);
reader.Close();
fs.Close();