I have a list of contracts that come in as xml strings like so:
<contract>
<CONTRACTID>CN0425-3</CONTRACTID>
<NAME>10425 - One-Year Contract</NAME>
<WHENMODIFIED>02/01/2020 08:18:30</WHENMODIFIED>
</contract>
<contract>
<CONTRACTID>CN0260-4</CONTRACTID>
<NAME>10260 - One-Year Contract</NAME>
<WHENMODIFIED>02/01/2020 08:18:30</WHENMODIFIED>
</contract>
I'm using this function to deserialize each item to an object:
public static T ParseXML<T>(this string #this) where T : class
{
var reader = XmlReader.Create(#this.Trim().ToStream(), new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Document });
var xmlRoot = new XmlRootAttribute { ElementName = typeof(T).Name.ToLower(), IsNullable = true };
return new XmlSerializer(typeof(T), xmlRoot).Deserialize(reader) as T;
}
Calling it like so:
// list is of type List<XElement> which contains a list of contracts
contracts.AddRange(from object e in list select e.ToString().ParseXML<Contract>() into e
select new Contract { Key = e.CONTRACTID, Name = e.NAME });
And here is my Contract class:
[SerializableAttribute]
[DesignerCategoryAttribute("code")]
[XmlTypeAttribute(AnonymousType = true)]
[XmlRootAttribute(Namespace = "", IsNullable = false)]
public class Contract
{
public string CONTRACTID { get; set; }
public string NAME { get; set; }
public string WHENMODIFIED { get; set; }
}
The problem is when I have a large list (1000+ contracts), the deserialization process is slow because it has to go through each xml item. I am wondering if it would optimize performance to combine all the xml items into one file and then deserialize the whole thing to a list of objects. I could potentially combine the list of xml items like this:
<contracts>
<contract>
<CONTRACTID>CN0425-3</CONTRACTID>
<NAME>10425 - One-Year Contract</NAME>
<WHENMODIFIED>02/01/2020 08:18:30</WHENMODIFIED>
</contract>
<contract>
<CONTRACTID>CN0260-4</CONTRACTID>
<NAME>10260 - One-Year Contract</NAME>
<WHENMODIFIED>02/01/2020 08:18:30</WHENMODIFIED>
</contract>
</contracts>
Do you guys know if that would benefit performance? And if so, how to combine the list of xml items and deserialize it?
Serialization is slow. Do comparison and see if xml linq below is faster :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var contracts = doc.Descendants("contract").Select(x => new Contract()
{
CONTRACTID = (string)x.Element("CONTRACTID"),
NAME = (string)x.Element("NAME"),
WHENMODIFIED = (DateTime)x.Element("WHENMODIFIED")
});
}
}
public class Contract
{
public string CONTRACTID { get; set; }
public string NAME { get; set; }
public DateTime WHENMODIFIED { get; set; }
}
}
I am working on this ASP.NET Api, where data is obtained through GET requests, formatted as XML.
right now, all xml nodes are generated using the code elements (class names, property names, etc). I can, if I wish, use attributes such as [XmlType(TypeName = "DesiredName")] to change those node names, but still, it will be a mapping 1-to-1 with the names I use in the code.
I have a specific object type which I would like to format using the actual runtime values, as opposed to the compile-time symbols.
Here are the classes:
public class RootClass
{
public string ID { get; set; }
public List<Property> Properties { get; set; }
}
public class Property
{
public string PropertyType { get; set; }
// Other Fields
}
Let's say that I have a couple properties, which have propertyTypes "Type1", "Type2", "Type3"
My desired Xml looks like this:
<RootClass>
<ID>23</ID>
<Properties>
<Type1>
<Property>
// Other Fields
</Property>
<Property>
// Other Fields
</Property>
</Type1>
<Type2>
<Property>
// Other Fields
</Property>
</Type2>
</Properties>
</RootType>
As you can see, one of the nodes would be named depending on the values, not the schema. I can easily do the grouping through code when mapping from the Model to the DTOs, and I have complete control over the DTO's classes, so I can change them as desired to get my expected XML.
First, is this even possible?
If it is, what should my class structure (and Attributes) look like to achieve this (Dictionaries of lists? custom collections?)
And if it isn't, What other options do I have to achieve something as close as possible to this?
Try Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
RootClass root = new RootClass()
{
ID = "23",
Properties = new List<Property>() {
new Property() { PropertyType = "Type1", Properties = new List<string>() { "A", "B", "C"} },
new Property() { PropertyType = "Type2", Properties = new List<string>() { "A", "B", "C"} }
}
};
XElement rootClass = new XElement("RootClass", new object[] {
new XElement("ID", root.ID),
new XElement("Properties")
});
XElement properties = rootClass.Element("Properties");
int count = 1;
foreach (Property property in root.Properties)
{
XElement type = new XElement(property.PropertyType);
properties.Add(type);
foreach (string p in property.Properties)
{
XElement strProperty = new XElement("Property", new object[] {
new XElement(p, count++)
});
type.Add(strProperty);
}
}
rootClass.Save(FILENAME);
}
}
public class RootClass
{
public string ID { get; set; }
public List<Property> Properties { get; set; }
}
public class Property
{
public string PropertyType { get; set; }
public List<string> Properties { get; set; }
}
}
How do I Deserialize this XML document:
<?xml version="1.0" encoding="utf-8"?>
<Cars>
<Car>
<StockNumber>1020</StockNumber>
<Make>Nissan</Make>
<Model>Sentra</Model>
</Car>
<Car>
<StockNumber>1010</StockNumber>
<Make>Toyota</Make>
<Model>Corolla</Model>
</Car>
<Car>
<StockNumber>1111</StockNumber>
<Make>Honda</Make>
<Model>Accord</Model>
</Car>
</Cars>
I have this:
[Serializable()]
public class Car
{
[System.Xml.Serialization.XmlElementAttribute("StockNumber")]
public string StockNumber{ get; set; }
[System.Xml.Serialization.XmlElementAttribute("Make")]
public string Make{ get; set; }
[System.Xml.Serialization.XmlElementAttribute("Model")]
public string Model{ get; set; }
}
.
[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
[XmlArrayItem(typeof(Car))]
public Car[] Car { get; set; }
}
.
public class CarSerializer
{
public Cars Deserialize()
{
Cars[] cars = null;
string path = HttpContext.Current.ApplicationInstance.Server.MapPath("~/App_Data/") + "cars.xml";
XmlSerializer serializer = new XmlSerializer(typeof(Cars[]));
StreamReader reader = new StreamReader(path);
reader.ReadToEnd();
cars = (Cars[])serializer.Deserialize(reader);
reader.Close();
return cars;
}
}
that don't seem to work :-(
How about you just save the xml to a file, and use xsd to generate C# classes?
Write the file to disk (I named it foo.xml)
Generate the xsd: xsd foo.xml
Generate the C#: xsd foo.xsd /classes
Et voila - and C# code file that should be able to read the data via XmlSerializer:
XmlSerializer ser = new XmlSerializer(typeof(Cars));
Cars cars;
using (XmlReader reader = XmlReader.Create(path))
{
cars = (Cars) ser.Deserialize(reader);
}
(include the generated foo.cs in the project)
Here's a working version. I changed the XmlElementAttribute labels to XmlElement because in the xml the StockNumber, Make and Model values are elements, not attributes. Also I removed the reader.ReadToEnd(); (that function reads the whole stream and returns a string, so the Deserialize() function couldn't use the reader anymore...the position was at the end of the stream). I also took a few liberties with the naming :).
Here are the classes:
[Serializable()]
public class Car
{
[System.Xml.Serialization.XmlElement("StockNumber")]
public string StockNumber { get; set; }
[System.Xml.Serialization.XmlElement("Make")]
public string Make { get; set; }
[System.Xml.Serialization.XmlElement("Model")]
public string Model { get; set; }
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("CarCollection")]
public class CarCollection
{
[XmlArray("Cars")]
[XmlArrayItem("Car", typeof(Car))]
public Car[] Car { get; set; }
}
The Deserialize function:
CarCollection cars = null;
string path = "cars.xml";
XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
StreamReader reader = new StreamReader(path);
cars = (CarCollection)serializer.Deserialize(reader);
reader.Close();
And the slightly tweaked xml (I needed to add a new element to wrap <Cars>...Net is picky about deserializing arrays):
<?xml version="1.0" encoding="utf-8"?>
<CarCollection>
<Cars>
<Car>
<StockNumber>1020</StockNumber>
<Make>Nissan</Make>
<Model>Sentra</Model>
</Car>
<Car>
<StockNumber>1010</StockNumber>
<Make>Toyota</Make>
<Model>Corolla</Model>
</Car>
<Car>
<StockNumber>1111</StockNumber>
<Make>Honda</Make>
<Model>Accord</Model>
</Car>
</Cars>
</CarCollection>
You have two possibilities.
Method 1. XSD tool
Suppose that you have your XML file in this location C:\path\to\xml\file.xml
Open Developer Command Prompt
You can find it in Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools
Or if you have Windows 8 can just start typing Developer Command Prompt in Start screen
Change location to your XML file directory by typing cd /D "C:\path\to\xml"
Create XSD file from your xml file by typing xsd file.xml
Create C# classes by typing xsd /c file.xsd
And that's it! You have generated C# classes from xml file in C:\path\to\xml\file.cs
Method 2 - Paste special
Required Visual Studio 2012+
Copy content of your XML file to clipboard
Add to your solution new, empty class file (Shift+Alt+C)
Open that file and in menu click Edit > Paste special > Paste XML As Classes
And that's it!
Usage
Usage is very simple with this helper class:
using System;
using System.IO;
using System.Web.Script.Serialization; // Add reference: System.Web.Extensions
using System.Xml;
using System.Xml.Serialization;
namespace Helpers
{
internal static class ParseHelpers
{
private static JavaScriptSerializer json;
private static JavaScriptSerializer JSON { get { return json ?? (json = new JavaScriptSerializer()); } }
public static Stream ToStream(this string #this)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(#this);
writer.Flush();
stream.Position = 0;
return stream;
}
public static T ParseXML<T>(this string #this) where T : class
{
var reader = XmlReader.Create(#this.Trim().ToStream(), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document });
return new XmlSerializer(typeof(T)).Deserialize(reader) as T;
}
public static T ParseJSON<T>(this string #this) where T : class
{
return JSON.Deserialize<T>(#this.Trim());
}
}
}
All you have to do now, is:
public class JSONRoot
{
public catalog catalog { get; set; }
}
// ...
string xml = File.ReadAllText(#"D:\file.xml");
var catalog1 = xml.ParseXML<catalog>();
string json = File.ReadAllText(#"D:\file.json");
var catalog2 = json.ParseJSON<JSONRoot>();
The following snippet should do the trick (and you can ignore most of the serialization attributes):
public class Car
{
public string StockNumber { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
[XmlRootAttribute("Cars")]
public class CarCollection
{
[XmlElement("Car")]
public Car[] Cars { get; set; }
}
...
using (TextReader reader = new StreamReader(path))
{
XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
return (CarCollection) serializer.Deserialize(reader);
}
See if this helps:
[Serializable()]
[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
[XmlArrayItem(typeof(Car))]
public Car[] Car { get; set; }
}
.
[Serializable()]
public class Car
{
[System.Xml.Serialization.XmlElement()]
public string StockNumber{ get; set; }
[System.Xml.Serialization.XmlElement()]
public string Make{ get; set; }
[System.Xml.Serialization.XmlElement()]
public string Model{ get; set; }
}
And failing that use the xsd.exe program that comes with visual studio to create a schema document based on that xml file, and then use it again to create a class based on the schema document.
I don't think .net is 'picky about deserializing arrays'. The first xml document is not well formed.
There is no root element, although it looks like there is. The canonical xml document has a root and at least 1 element (if at all). In your example:
<Root> <-- well, the root
<Cars> <-- an element (not a root), it being an array
<Car> <-- an element, it being an array item
...
</Car>
</Cars>
</Root>
try this block of code if your .xml file has been generated somewhere in disk and if you have used List<T>:
//deserialization
XmlSerializer xmlser = new XmlSerializer(typeof(List<Item>));
StreamReader srdr = new StreamReader(#"C:\serialize.xml");
List<Item> p = (List<Item>)xmlser.Deserialize(srdr);
srdr.Close();`
Note: C:\serialize.xml is my .xml file's path. You can change it for your needs.
For Beginners
I found the answers here to be very helpful, that said I still struggled (just a bit) to get this working. So, in case it helps someone I'll spell out the working solution:
XML from Original Question. The xml is in a file Class1.xml, a path to this file is used in the code to locate this xml file.
I used the answer by #erymski to get this working, so created a file called Car.cs and added the following:
using System.Xml.Serialization; // Added
public class Car
{
public string StockNumber { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
[XmlRootAttribute("Cars")]
public class CarCollection
{
[XmlElement("Car")]
public Car[] Cars { get; set; }
}
The other bit of code provided by #erymski ...
using (TextReader reader = new StreamReader(path))
{
XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
return (CarCollection) serializer.Deserialize(reader);
}
... goes into your main program (Program.cs), in static CarCollection XCar() like this:
using System;
using System.IO;
using System.Xml.Serialization;
namespace ConsoleApp2
{
class Program
{
public static void Main()
{
var c = new CarCollection();
c = XCar();
foreach (var k in c.Cars)
{
Console.WriteLine(k.Make + " " + k.Model + " " + k.StockNumber);
}
c = null;
Console.ReadLine();
}
static CarCollection XCar()
{
using (TextReader reader = new StreamReader(#"C:\Users\SlowLearner\source\repos\ConsoleApp2\ConsoleApp2\Class1.xml"))
{
XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
return (CarCollection)serializer.Deserialize(reader);
}
}
}
}
Hope it helps :-)
Kevin's anser is good, aside from the fact, that in the real world, you are often not able to alter the original XML to suit your needs.
There's a simple solution for the original XML, too:
[XmlRoot("Cars")]
public class XmlData
{
[XmlElement("Car")]
public List<Car> Cars{ get; set; }
}
public class Car
{
public string StockNumber { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}
And then you can simply call:
var ser = new XmlSerializer(typeof(XmlData));
var data = (XmlData)ser.Deserialize(XmlReader.Create(PathToCarsXml));
One liner:
var object = (Cars)new XmlSerializer(typeof(Cars)).Deserialize(new StringReader(xmlString));
Try this Generic Class For Xml Serialization & Deserialization.
public class SerializeConfig<T> where T : class
{
public static void Serialize(string path, T type)
{
var serializer = new XmlSerializer(type.GetType());
using (var writer = new FileStream(path, FileMode.Create))
{
serializer.Serialize(writer, type);
}
}
public static T DeSerialize(string path)
{
T type;
var serializer = new XmlSerializer(typeof(T));
using (var reader = XmlReader.Create(path))
{
type = serializer.Deserialize(reader) as T;
}
return type;
}
}
How about a generic class to deserialize an XML document
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Generic class to load any xml into a class
// used like this ...
// YourClassTypeHere InfoList = LoadXMLFileIntoClass<YourClassTypeHere>(xmlFile);
using System.IO;
using System.Xml.Serialization;
public static T LoadXMLFileIntoClass<T>(string xmlFile)
{
T returnThis;
XmlSerializer serializer = new XmlSerializer(typeof(T));
if (!FileAndIO.FileExists(xmlFile))
{
Console.WriteLine("FileDoesNotExistError {0}", xmlFile);
}
returnThis = (T)serializer.Deserialize(new StreamReader(xmlFile));
return (T)returnThis;
}
This part may, or may not be necessary. Open the XML document in Visual Studio, right click on the XML, choose properties. Then choose your schema file.
The idea is to have all level being handled for deserialization
Please see a sample solution that solved my similar issue
<?xml version="1.0" ?>
<TRANSACTION_RESPONSE>
<TRANSACTION>
<TRANSACTION_ID>25429</TRANSACTION_ID>
<MERCHANT_ACC_NO>02700701354375000964</MERCHANT_ACC_NO>
<TXN_STATUS>F</TXN_STATUS>
<TXN_SIGNATURE>a16af68d4c3e2280e44bd7c2c23f2af6cb1f0e5a28c266ea741608e72b1a5e4224da5b975909cc43c53b6c0f7f1bbf0820269caa3e350dd1812484edc499b279</TXN_SIGNATURE>
<TXN_SIGNATURE2>B1684258EA112C8B5BA51F73CDA9864D1BB98E04F5A78B67A3E539BEF96CCF4D16CFF6B9E04818B50E855E0783BB075309D112CA596BDC49F9738C4BF3AA1FB4</TXN_SIGNATURE2>
<TRAN_DATE>29-09-2015 07:36:59</TRAN_DATE>
<MERCHANT_TRANID>150929093703RUDZMX4</MERCHANT_TRANID>
<RESPONSE_CODE>9967</RESPONSE_CODE>
<RESPONSE_DESC>Bank rejected transaction!</RESPONSE_DESC>
<CUSTOMER_ID>RUDZMX</CUSTOMER_ID>
<AUTH_ID />
<AUTH_DATE />
<CAPTURE_DATE />
<SALES_DATE />
<VOID_REV_DATE />
<REFUND_DATE />
<REFUND_AMOUNT>0.00</REFUND_AMOUNT>
</TRANSACTION>
</TRANSACTION_RESPONSE>
The above XML is handled in two level
[XmlType("TRANSACTION_RESPONSE")]
public class TransactionResponse
{
[XmlElement("TRANSACTION")]
public BankQueryResponse Response { get; set; }
}
The Inner level
public class BankQueryResponse
{
[XmlElement("TRANSACTION_ID")]
public string TransactionId { get; set; }
[XmlElement("MERCHANT_ACC_NO")]
public string MerchantAccNo { get; set; }
[XmlElement("TXN_SIGNATURE")]
public string TxnSignature { get; set; }
[XmlElement("TRAN_DATE")]
public DateTime TranDate { get; set; }
[XmlElement("TXN_STATUS")]
public string TxnStatus { get; set; }
[XmlElement("REFUND_DATE")]
public DateTime RefundDate { get; set; }
[XmlElement("RESPONSE_CODE")]
public string ResponseCode { get; set; }
[XmlElement("RESPONSE_DESC")]
public string ResponseDesc { get; set; }
[XmlAttribute("MERCHANT_TRANID")]
public string MerchantTranId { get; set; }
}
Same Way you need multiple level with car as array
Check this example for multilevel deserialization
If you're getting errors using xsd.exe to create your xsd file, then use the XmlSchemaInference class as mentioned on msdn. Here's a unit test to demonstrate:
using System.Xml;
using System.Xml.Schema;
[TestMethod]
public void GenerateXsdFromXmlTest()
{
string folder = #"C:\mydir\mydata\xmlToCSharp";
XmlReader reader = XmlReader.Create(folder + "\some_xml.xml");
XmlSchemaSet schemaSet = new XmlSchemaSet();
XmlSchemaInference schema = new XmlSchemaInference();
schemaSet = schema.InferSchema(reader);
foreach (XmlSchema s in schemaSet.Schemas())
{
XmlWriter xsdFile = new XmlTextWriter(folder + "\some_xsd.xsd", System.Text.Encoding.UTF8);
s.Write(xsdFile);
xsdFile.Close();
}
}
// now from the visual studio command line type: xsd some_xsd.xsd /classes
You can just change one attribute for you Cars car property from XmlArrayItem to XmlElment. That is, from
[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
[XmlArrayItem(typeof(Car))]
public Car[] Car { get; set; }
}
to
[System.Xml.Serialization.XmlRootAttribute("Cars", Namespace = "", IsNullable = false)]
public class Cars
{
[XmlElement("Car")]
public Car[] Car { get; set; }
}
My solution:
Use Edit > Past Special > Paste XML As Classes to get the class in your code
Try something like this: create a list of that class (List<class1>), then use the XmlSerializer to serialize that list to a xml file.
Now you just replace the body of that file with your data and try to deserialize it.
Code:
StreamReader sr = new StreamReader(#"C:\Users\duongngh\Desktop\Newfolder\abc.txt");
XmlSerializer xml = new XmlSerializer(typeof(Class1[]));
var a = xml.Deserialize(sr);
sr.Close();
NOTE: you must pay attention to the root name, don't change it. Mine is "ArrayOfClass1"
I have the following xml file.
<a>
<b>
<c>val1</c>
<d>val2</d>
</b>
<b>
<c>val3</c>
<d>val4</d>
</b>
<a>
I want to deserialize this into a class and I want to access them with the objects of the class created. I am using C#. I am able to deserialize and get the value into the object of class ‘a’ (the <a> tag). but how to access the value of <b> from this object?
I did the following coding:
[Serializable()]
[XmlRoot("a")]
public class a
{
[XmlArray("a")]
[XmlArrayItem("b", typeof(b))]
public b[] bb{ get; set; }
}
[Serializable()]
public class b
{
[XmlElement("c")]
public string c{ get; set; }
[XmlElement("d")]
public string d{ get; set; }
}
class Program
{
static void Main(string[] args)
{
a i = null;
string path = "test.xml";
XmlSerializer serializer = new XmlSerializer(typeof(a));
StreamReader reader = new StreamReader(path);
i = (a)serializer.Deserialize(reader);
reader.Close();
//i want to print all b tags here
Console.Read();
}
}
For this to work you can make the following change
public class a
{
[XmlElement("b")]
public b[] bb{ get; set; }
}
By using the XmlElement attribute on the array, you are essentially telling the serializer that the array elements should be serialize/deserialized as direct child elements of the current element.
Here is a working example, I put the XML in a string just to make the example self contained.
using System;
using System.IO;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
#"<a>
<b>
<c>val1</c>
<d>val2</d>
</b>
<b>
<c>val3</c>
<d>val4</d>
</b>
</a>";
XmlSerializer xs = new XmlSerializer(typeof(a));
a i = (a)xs.Deserialize(new StringReader(xml));
if (i != null && i.bb != null && i.bb.Length > 0)
{
Console.WriteLine(i.bb[0].c);
}
else
{
Console.WriteLine("Something went wrong!");
}
Console.ReadKey();
}
}
[XmlRoot("a")]
public class a
{
[XmlElement("b")]
public b[] bb { get; set; }
}
public class b
{
[XmlElement("c")]
public string c { get; set; }
[XmlElement("d")]
public string d { get; set; }
}
}
When in doubt with creating your xml serialization classes, i find the easiest way to solve the problem is to:
dump all your dummy data into an XML file
run xsd.exe to create a .xsd schema file
run xsd.exe on your schema file to create a class file
i wrote a quick tutorial on it in a blog post a while ago:
http://www.diaryofaninja.com/blog/2010/05/07/make-your-xml-stronglytyped-because-you-can-and-its-easy
it takes less than a minute and you can then easily tweak things from there. XSD.exe is your friend
I find the easiest way to solve the problem is to change your definition of classes a and b to the following
public class b {
public string c { get; set; }
public string d { get; set; }
}
[XmlRoot(Namespace="", ElementName="a")]
public class a : List<b> { }
then your program will work. Optionally you can add to the class b the attribute [XmlRoot (Namespace = "", ElementName = "b")]
class Program
{
static void Main(string[] args)
{
string employeedata = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><tag><name>test</bar></nmae>";//demo xml data
using (TextReader sr = new StringReader(employeedata))
{
XmlSerializer serializer = new XmlSerializer(typeof(Employee));//pass type name in XmlSerializer constructor here
Employee response = (Employee)serializer.Deserialize(sr);
Console.WriteLine(response.name);
}
}
}
[System.Xml.Serialization.XmlRoot("tag")]
public class Employee
{
public string name { get; set; }
}
Change if block (from Chris Tyler's answer) like below.
if (i != null && i.bb != null && i.bb.Length > 0)
{
foreach (b t in i.bb)
{
Console.WriteLine(t.c);
Console.WriteLine(t.d);
}
}
then it will give you below result:
val1
val2
val3
val4
I have an XML file
<searchResponse requestID=“500” status=“success”>
<pso>
<psoID ID=“770e8400-e29b-41d4-a716-446655448549”
targetID=“mezeoAccount”/>
<data>
<email>user2#example.net</email>
<quotaMeg>100</quotaMeg>
<quotaUsed>23</quotaUsed>
<realm>Mezeo</realm>
<path>/san1/</path>
<billing>user2</billing>
<active>true</active>
<unlocked>true</unlocked>
<allowPublic>true</allowPublic>
<bandwidthQuota>1000000000</bandwidthQuota>
<billingDay>1</billingDay>
</data>
</pso>
</searchRequest>
and I want to extract the data into a single business object. Am I better to go
MezeoAccount mcspAccount = new MezeoAccount();
mcspAccount.PsoID = doc.Element("psoID").Attribute("ID").Value;
mcspAccount.Email = doc.Element("email").Value;
...
or build a list even though I know there is only 1 record in the file?
var psoQuery = from pso in doc.Descendants("data")
select new MezeoAccount {
PsoID = pso.Parent.Element("psoID").Attribute("ID").Value,
Email = pso.Element("email").Value,
... };
What would people suggest would be the more correct way, or a better way even, if I missed something.
If you know that your xml only will contain one record of the data in mind you shouldn't create a list for it. So your first example looks fine.
A pattern I personally use is something like this:
public class MezeoAccount
{
public string PsoID { get; set; }
public string Email { get; set; }
public static MezeoAccount CreateFromXml(XmlDocument xml)
{
return new MezeoAccount()
{
PsoID = xml.Element("psoID").Attribute("ID").Value,
Email = doc.Element("email").Value;
};
}
}
//Usage
var mezeoAccount = MezeoAccount.CreateFromXml(xml);
It looks like you didn't get a working answer to this question. Assuming that there can only be one account in the XML file, I would do it like this:
using System;
using System.Linq;
using System.Xml.Linq;
public class MezeoAccount
{
public string PsoId { get; set; }
public string Email { get; set; }
public int QuotaMeg { get; set; }
// Other properties...
}
public class Program
{
public static void Main()
{
XDocument doc = XDocument.Load("input.xml");
XElement pso = doc.Element("searchResponse").Element("pso");
XElement data = pso.Element("data");
MezeoAccount x = new MezeoAccount
{
PsoId = pso.Element("psoID").Attribute("ID").Value,
Email = data.Element("email").Value,
QuotaMeg = int.Parse(data.Element("quotaMeg").Value),
// Other properties...
};
}
}