I am creating a system that stores vehicle data. When I serialize the data using Xml serialization, I get the correct format as shown in the example below:
<?xml version="1.0"?>
<ArrayOfVehicle xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Vehicle>
<Registration>fake1</Registration>
<Model>123</Model>
<Make>test</Make>
<Year>1999</Year>
<Cost>100</Cost>
</Vehicle>
<Vehicle>
<Registration>fake2</Registration>
<Model>321</Model>
<Make>123</Make>
<Year>2000</Year>
<Cost>321</Cost>
</Vehicle>
</ArrayOfVehicle>
The serialization uses a list of vehicles that have the attributes seen in the Xml file. I am trying to figure out how I can delete a vehicle from the list and serialize it back to the Xml file without breaking the format shown above.
The method that I have tried to use to delete the records from the list and serialize and deserialize the data, but when I remove and item, it breaks the format. This is what the Xml file looks like when I remove an item from the list and serialize it:
fake1 123 test 1999 100
Here is my code for removing an item:
for (int i = Business.VehicleList.Count - 1; i >= 0; i--)
{ //Where Business.VehicleList is my list
if (Business.VehicleList[i].Registration == registration)
{
Business.VehicleList.RemoveAt(i);
Business.Save(); //Method for serialization
}
}
Here is the error it throws when I try to deserialize the data again:
System.InvalidOperationException: 'There is an error in XML document (10, 19). XmlException: There are multiple root elements. Line 10, position 19.'
These are my serialization and deserialization methods:
public static void Retrieve()
{
using (FileStream fileStream = new FileStream("C:\\temp\\data.xml", FileMode.OpenOrCreate))
{
using (var reader = new StreamReader(fileStream))
{
if (fileStream.Length <= 0)
{
return;
}
else
{
XmlSerializer deserializer = new XmlSerializer(typeof(List<Vehicle>),
new XmlRootAttribute("ArrayOfVehicle"));
_vehicleList = (List<Vehicle>)deserializer.Deserialize(reader); //This is where the error is thrown
}
}
}
}
public static void Save()
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Vehicle>));
using (FileStream fileStream = new FileStream("C:\\temp\\data.xml", FileMode.Open))
{
serializer.Serialize(fileStream, VehicleList);
fileStream.Close();
}
}
Any suggestions on how to remove a vehicle from my list without it breaking the Xml file?
Here is the source after I tried deleting an item from the vehicle string
<?xml version="1.0"?>
<ArrayOfVehicle xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Vehicle>
<Registration>123</Registration>
<Model>123</Model>
<Make>23</Make>
<Year>2000</Year>
<Cost>123</Cost>
</Vehicle>
</ArrayOfVehicle><Registration>1321</Registration>
<Model>123123</Model>
<Make>312312</Make>
<Year>2000</Year>
<Cost>321</Cost>
</Vehicle>
</ArrayOfVehicle>
In the Save method, new FileStream("C:\\temp\\data.xml", FileMode.Open) will open the existing file without truncating it. So after you write the new XML data to the file, there will be remnants of the old content if the new content is shorter than the old one.
Changing this to new FileStream("C:\\temp\\data.xml", FileMode.Create) will fix the issue.
I think it's because you are trying to de-serialize a malformed xml. Please first, make sure that your serialization method produces correct xml. The reason may be because of closing the stream inside using statement. And also serializing the list before for-loop finishes.
Try removing fileStream.Close(); and also moving Business.Save(); to outside of for-loop.
Here, I made a fiddle with same conditions and it works.
I have many .xsd files for many xml schemas
example
XML 1.0 - xml_1_0.xml
<?xml version="1.0" encoding="UTF-8"?>
<cars version="1.00">
<car>Honda</car>
<car>Ferrari</car>
</cars>
XML 2.0 - xml_2_0.xml
<?xml version="1.0" encoding="UTF-8"?>
<cars version="2.00">
<car>
<name>Honda</name>
<color>White</color>
</car>
<car>
<name>Honda</name>
<color>Red</color>
</car>
</cars>
I create my classes from .xsd like this
xsd.exe cars_1_0.xsd /c
xsd.exe cars_2_0.xsd /c
And Deserialize like this:
foreach(string file in files) {
XmlDocument doc = new XmlDocument();
doc.Load(file);
string version = doc.SelectSingleNode("/Cars/#version").Value;
if(version == "1.00")
{
Stream reader = new FileStream(file, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars));
v1.Cars XML = new v1.Cars();
XML = (v1.Cars)serializer.Deserialize(reader);
}
else if(version == "2.00")
{
Stream reader = new FileStream(file, FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars));
v2.Cars XML = new v2.Cars();
XML = (v2.Cars)serializer.Deserialize(reader);
}
}
Does anyone know a better way to do this, or have a better performance?
You have several options, depending on how far you want to take this. One fairly non invasive option would be to not use XmlDocument and avoid loading the stream more than once. For example, your existing code could be simplified/streamlined to :
foreach (string file in files)
{
using (var stream = new FileStream(file, FileMode.Open))
{
var settings = new XmlReaderSettings();
settings.CloseInput = false;
string version = "";
using (var xmlReader = XmlReader.Create(stream))
{
if (xmlReader.ReadToFollowing("Cars"))
{
version = xmlReader.GetAttribute("version");
}
else
{
throw new XmlException("Could not get 'version' attribute of 'Cars' root element!");
}
}
stream.Position = 0;
if (version == "1.00")
{
XmlSerializer serializer = new XmlSerializer(typeof(v1.Cars));
v1.Cars XML = new v1.Cars();
XML = (v1.Cars)serializer.Deserialize(stream);
}
else if (version == "2.00")
{
XmlSerializer serializer = new XmlSerializer(typeof(v2.Cars));
v2.Cars XML = new v2.Cars();
XML = (v2.Cars)serializer.Deserialize(stream);
}
}
}
Since you're just reading off the root element, you might even be able to get away with deserializing from the XmlReader and not have to reset the position on the FileStream.
This avoids the overhead of loading the entire file twice (once for XmlDocument, then again for XmlSerializer) - and particularly avoids the memory overhead of creating a DOM for each document.
A more nuclear option would be implementing IXmlSerializable on a set of custom classes, which would have custom logic in the ReadXml methods to parse the version attribute and instantiate the correct child type(s) - e.g. a CarCollection class that has a List<Car> property, where Car is an abstract class that has CarV1 and CarV2 as descendants. This would be about as efficient as you could get (and offer very fine grained control over your class hierarchy design), but would eliminate the possibility of using xsd.exe to generate your classes.
There are lots of examples on the web of transforming an XML file to a different format using an XSLT file, like the following:
XslTransform myXslTransform = new XslTransform();
XsltSettings myXsltSettings = new XsltSettings();
myXsltSettings.EnableDocumentFunction = true;
myXslTransform.Load("transform.xsl");
myXslTransform.Transform("input.xml", "output.xml");
However this is only a partial answer, I would like to be able to get the XML input data from a web form and use that as the input xml data instead of an '.xml' file, but have not found any concrete examples. Using Visual Studio I see Load methods that accept XmlReader objects as parameters but I do not know how to create one of those using the data from a form and TextBox control. It would be very helpful if someone could provide an example of transforming XML using form data instead of an input file.
Create a class and populate an instance of this class during postback from your form data and serialize it ( convert it to xml)
Here is console example for you
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace Stackoverflow
{
public class Program
{
static void Main(string[] args)
{
var p = new Person
{
FirstName = "Daniel", /// in your case you get it from the form
LastName = "Endeg"
};
var x = new XmlSerializer(p.GetType());
x.Serialize(Console.Out, p);
Console.WriteLine();
Console.ReadLine();
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
Please note that XslTransform is obsolete since .NET 2.0, you should use XslCompiledTransform instead. And if you want to use XslSettings then make sure you pass them in to the XslCompiledTransform's Load method (e.g. http://msdn.microsoft.com/en-us/library/ms163425.aspx), simply creating it does not make sense.
As for parsing XML you have in a string variable or property (like the Text property of a TextBox) you have lots of options, you can use an XmlReader over a StringReader e.g.
XslCompiledTransform proc = new XslCompiledTransform();
proc.Load("sheet.xsl");
using (StringReader sr = new StringReader(TextBox1.Text))
{
using (XmlReader xr = XmlReader.Create(sr))
{
proc.Transform(xr, null, Response.Output);
}
}
Or you can create an XPathDocument or XmlDocument or XDocument from the string and use an overload of the Transform method that takes an IXPathNavigable as the first argument.
Ok, with some help from Visual Studio auto-complete which lists the parameters for constructors and methods, I was able to complete a working answer to the problem above, using strings for input and output in an Xslt transform operation. Yay. The example answer below assumes you have three strings containing the Xslt text data and the input Xml text data and output Xml data:
string XsltText;
string InputXML;
string OutputXml;
// define the xslt from a string
TextReader myXsltText = new StringReader(XsltText);
XmlReader myXslt = new XmlTextReader(myXsltText);
// define the input xml from a string
TextReader myXmlText = new StringReader(InputXML);
XmlReader myInputXml = new XmlTextReader(myXmlText);
// define the output XmlWriter for the results of the transform
TextWriter myOutputXmlTextWriter = new StringWriter();
XmlWriter myOutputXml = new XmlTextWriter(myOutputXmlTextWriter);
XslCompiledTransform myXslTransform = new XslCompiledTransform();
XsltSettings myXsltSettings = new XsltSettings();
myXsltSettings.EnableDocumentFunction = true;
myXslTransform.Load(myXslt);
myXslTransform.Transform(myInputXml, myOutputXml);
// the result from the transform comes from the TextWriter object
OutputXml = myOutputXmlTextWriter.ToString();
// clean up writers
myOutputXml.Flush();
myOutputXmlTextWriter.Close();
myOutputXml.Close();
To get this code working with a web form, all you have to do is get the strings from the value (Text) of the form elements (controls), for the input XMl and Xslt you could use TextBox controls, and to display the results you could use a label, all very useful, if anyone has a better answer please feel free to let me know.
I am fairly new to XML in .net. As part of my task i need to create the class which can be serialized to XML. I have an sample XML file with all the tags(the class should produce XML similar to the sample XML file ). what would be best approach to create the class from XML file?
Thank you in advance!!
You can use XSD.exe to create a .cs file from .xml.
http://msdn.microsoft.com/en-us/library/x6c1kb0s%28VS.71%29.aspx
At the command line:
xsd myFile.xml
xsd myFile.xsd
The first line will generate a schema definition file (xsd), the second file should generate a .cs file. I'm not sure if the syntax is exact, but it should get you started.
Working backwards might help -- create your class first, then serialize and see what you get.
For the simplest classes it's actually quite easy. You can use XmlSerializer to serialize, like:
namespace ConsoleApplication1
{
public class MyClass
{
public string SomeProperty
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
TextWriter writer = new StreamWriter(#"c:\temp\class.xml");
MyClass firstInstance = new MyClass();
firstInstance.SomeProperty = "foo"; // etc
serializer.Serialize(writer, firstInstance);
writer.Close();
FileStream reader = new FileStream(#"c:\temp\class.xml", FileMode.Open);
MyClass secondInstance = (MyClass)serializer.Deserialize(reader);
reader.Close();
}
}
}
This will write a serialized representation of your class in XML to "c:\temp\class.xml". You could take a look and see what you get. In reverse, you can use serializer.Deserialize to instantiate the class from "c:\temp\class.xml".
You can modify the behaviour of he serialization, and deal with unexpected nodes, etc -- take a look at the XmlSerializer MSDN page for example.
here's a good example how to serialize/deserialize an object. http://sharpertutorials.com/serialization/
I am receiving XML strings over a socket, and would like to convert these to C# objects.
The messages are of the form:
<msg>
<id>1</id>
<action>stop</action>
</msg>
How can this be done?
You need to use the xsd.exe tool which gets installed with the Windows SDK into a directory something similar to:
C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin
And on 64-bit computers:
C:\Program Files (x86)\Microsoft SDKs\Windows\v6.0A\bin
And on Windows 10 computers:
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin
On the first run, you use xsd.exe and you convert your sample XML into a XSD file (XML schema file):
xsd yourfile.xml
This gives you yourfile.xsd, which in a second step, you can convert again using xsd.exe into a C# class:
xsd yourfile.xsd /c
This should give you a file yourfile.cs which will contain a C# class that you can use to deserialize the XML file you're getting - something like:
XmlSerializer serializer = new XmlSerializer(typeof(msg));
msg resultingMessage = (msg)serializer.Deserialize(new XmlTextReader("yourfile.xml"));
Should work pretty well for most cases.
Update: the XML serializer will take any stream as its input - either a file or a memory stream will be fine:
XmlSerializer serializer = new XmlSerializer(typeof(msg));
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString));
msg resultingMessage = (msg)serializer.Deserialize(memStream);
or use a StringReader:
XmlSerializer serializer = new XmlSerializer(typeof(msg));
StringReader rdr = new StringReader(inputString);
msg resultingMessage = (msg)serializer.Deserialize(rdr);
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+ with .Net Framework >= 4.5 as project target and 'Windows Communication Foundation' individual component installed
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>();
Try this method to Convert Xml to an object. It is made for exactly what you are doing:
protected T FromXml<T>(String xml)
{
T returnedXmlClass = default(T);
try
{
using (TextReader reader = new StringReader(xml))
{
try
{
returnedXmlClass =
(T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
catch (InvalidOperationException)
{
// String passed is not XML, simply return defaultXmlClass
}
}
}
catch (Exception ex)
{
}
return returnedXmlClass ;
}
Call it using this code:
YourStrongTypedEntity entity = FromXml<YourStrongTypedEntity>(YourMsgString);
Simply Run Your Visual Studio 2013 as Administration ...
Copy the content of your Xml file..
Go to Visual Studio 2013 > Edit > Paste Special > Paste Xml as C# Classes
It will create your c# classes according to your Xml file content.
Just in case anyone might find this useful:
public static class XmlConvert
{
public static string SerializeObject<T>(T dataObject)
{
if (dataObject == null)
{
return string.Empty;
}
try
{
using (StringWriter stringWriter = new System.IO.StringWriter())
{
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(stringWriter, dataObject);
return stringWriter.ToString();
}
}
catch (Exception ex)
{
return string.Empty;
}
}
public static T DeserializeObject<T>(string xml)
where T : new()
{
if (string.IsNullOrEmpty(xml))
{
return new T();
}
try
{
using (var stringReader = new StringReader(xml))
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
}
catch (Exception ex)
{
return new T();
}
}
}
You can call it using:
MyCustomObject myObject = new MyCustomObject();
string xmlString = XmlConvert.SerializeObject(myObject);
myObject = XmlConvert.DeserializeObject<MyCustomObject>(xmlString);
You can generate class as described above, or write them manually:
[XmlRoot("msg")]
public class Message
{
[XmlElement("id")]
public string Id { get; set; }
[XmlElement("action")]
public string Action { get; set; }
}
Then you can use ExtendedXmlSerializer to serialize and deserialize.
Instalation
You can install ExtendedXmlSerializer from nuget or run the following command:
Install-Package ExtendedXmlSerializer
Serialization:
var serializer = new ConfigurationContainer().Create();
var obj = new Message();
var xml = serializer.Serialize(obj);
Deserialization
var obj2 = serializer.Deserialize<Message>(xml);
This serializer support:
Deserialization xml from standard XMLSerializer
Serialization class, struct, generic class, primitive type, generic list and dictionary, array, enum
Serialization class with property interface
Serialization circular reference and reference Id
Deserialization of old version of xml
Property encryption
Custom serializer
Support XmlElementAttribute and XmlRootAttribute
POCO - all configurations (migrations, custom serializer...) are outside the class
ExtendedXmlSerializer support .NET 4.5 or higher and .NET Core. You can integrate it with WebApi and AspCore.
You can use xsd.exe to create schema bound classes in .Net then XmlSerializer to Deserialize the string : http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.deserialize.aspx
Simplifying Damian's great answer,
public static T ParseXml<T>(this string value) where T : class
{
var xmlSerializer = new XmlSerializer(typeof(T));
using (var textReader = new StringReader(value))
{
return (T) xmlSerializer.Deserialize(textReader);
}
}
I have gone through all the answers as at this date (2020-07-24), and there has to be a simpler more familiar way to solve this problem, which is the following.
Two scenarios... One is if the XML string is well-formed, i.e. it begins with something like <?xml version="1.0" encoding="utf-16"?> or its likes, before encountering the root element, which is <msg> in the question. The other is if it is NOT well-formed, i.e. just the root element (e.g. <msg> in the question) and its child nodes only.
Firstly, just a simple class that contains the properties that match, in case-insensitive names, the child nodes of the root node in the XML. So, from the question, it would be something like...
public class TheModel
{
public int Id { get; set; }
public string Action { get; set; }
}
The following is the rest of the code...
// These are the key using statements to add.
using Newtonsoft.Json;
using System.Xml;
bool isWellFormed = false;
string xml = = #"
<msg>
<id>1</id>
<action>stop</action>
</msg>
";
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(xml);
if (isWellFormed)
{
xmlDocument.RemoveChild(xmlDocument.FirstChild);
/* i.e. removing the first node, which is the declaration part.
Also, if there are other unwanted parts in the XML,
write another similar code to locate the nodes
and remove them to only leave the desired root node
(and its child nodes).*/
}
var serializedXmlNode = JsonConvert.SerializeXmlNode(
xmlDocument,
Newtonsoft.Json.Formatting.Indented,
true
);
var theDesiredObject = JsonConvert.DeserializeObject<TheModel>(serializedXmlNode);
I know this question is old, but I stumbled into it and I have a different answer than, well, everyone else :-)
The usual way (as the commenters above mention) is to generate a class and de-serialize your xml.
But (warning: shameless self-promotion here) I just published a nuget package, here, with which you don't have to. You just go:
string xml = System.IO.File.ReadAllText(#"C:\test\books.xml");
var book = Dandraka.XmlUtilities.XmlSlurper.ParseText(xml);
That is literally it, nothing else needed. And, most importantly, if your xml changes, your object changes automagically as well.
If you prefer to download the dll directly, the github page is here.
Create a DTO as CustomObject
Use below method to convert XML String to DTO using JAXB
private static CustomObject getCustomObject(final String ruleStr) {
CustomObject customObject = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(CustomObject.class);
final StringReader reader = new StringReader(ruleStr);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
customObject = (CustomObject) jaxbUnmarshaller.unmarshal(reader);
} catch (JAXBException e) {
LOGGER.info("getCustomObject parse error: ", e);
}
return customObject;
}
If you have the xsd of the xml message then you can generate c# classes using the .Net xsd.exe tool.
This .Net classes can then be used to generate the xml.
In addition to the other answers here you can naturally use the XmlDocument class, for XML DOM-like reading, or the XmlReader, fast forward-only reader, to do it "by hand".
Another way with an Advanced xsd to c# classes generation Tools : xsd2code.com. This tool is very handy and powerfull. It has a lot more customisation than the xsd.exe tool from Visual Studio. Xsd2Code++ can be customised to use Lists or Arrays and supports large schemas with a lot of Import statements.
Note of some features,
Generates business objects from XSD Schema or XML file to flexible C#
or Visual Basic code.
Support Framework 2.0 to 4.x
Support strong typed collection (List, ObservableCollection, MyCustomCollection).
Support automatic properties.
Generate XML read and write methods (serialization/deserialization).
Databinding support (WPF, Xamarin).
WCF (DataMember attribute).
XML Encoding support (UTF-8/32, ASCII, Unicode, Custom).
Camel case / Pascal Case support.
restriction support ([StringLengthAttribute=true/false], [RegularExpressionAttribute=true/false],
[RangeAttribute=true/false]).
Support large and complex XSD file.
Support of DotNet Core & standard
public string Serialize<T>(T settings)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StringWriter outStream = new StringWriter();
serializer.Serialize(outStream, settings);
return outStream.ToString();
}