227

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?

3

15 Answers 15

315

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);
Sign up to request clarification or add additional context in comments.

14 Comments

Thanks for the detailed explanation. In my case, the XML is coming over a socket, and is a string. How would I de-serialize a string instead of an XML file?
@Steve: You can open a StringReader and pass the Deserialize method. StringReader derives from TextReader.
Would you prefer your approach to the one Fahad mentioned using Linq?
@Steve: yes, I would - deserializing into an object and being able to poke at the object's properties seems a lot easier than doing a lot of wiggling with XML elements, attributes, child nodes etc. Linq-to-XML is great if the XML is irregular and changes all the time, or not known ahead of time.
This web site is much easier than the xsd tool IMO: xmltocsharp.azurewebsites.net
|
275

You have two possibilities.

Method 1. XSD tool


Suppose that you have your XML file in this location C:\path\to\xml\file.xml

  1. 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
  2. Change location to your XML file directory by typing cd /D "C:\path\to\xml"
  3. Create XSD file from your xml file by typing xsd file.xml
  4. 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

  1. Copy content of your XML file to clipboard
  2. Add to your solution new, empty class file (Shift+Alt+C)
  3. Open that file and in menu click Edit > Paste special > Paste XML As Classes
    enter image description here

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>();

9 Comments

cheers. re: method 2, you have to target .net 4.5 else the option's not available.
Method 2 is ridiculously useful! Thanks for that. I had no idea that existed.
Kudos for the method 2, works like a charm. Great when trying to simply parse a XML programmatically without having to implement boring classes.
You should make "Paste Special" as a first method- it's the simplest one. Limitation ".Net Framework >= 4.5" is not important in 2017.
The "Paste XML as classes" requires the WCF workload for Visual Studio installed.
|
57

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);

4 Comments

Got this error xmlns=''> was not expected."}, any idea ?
Problem is, you need to have your class perfectly formed in advance. Maybe a function that outputs a class when given XML? xsd.exe is hit & miss (mostly miss for complex stuff)...
Oh my god I spent hours dealing with .nets xml serializer, and this worked right out of the gate.
in case of "was not expected" error use solution above with Edit -> Paste Special instead of manually creating classes
14

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.

Comments

12

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);

3 Comments

Missing semicolon at XmlConvert.SerializeObject(myObject) :)
@TimMaes Thanks! Just updated the snippet! (1975 days later) ;-)
Couldn't wait a day longer :)
10

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.

1 Comment

Excellent post! I updated the code to modernize it according to the documentation github.com/wojtpl2/ExtendedXmlSerializer
3

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

Comments

3

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);
    }
}

Comments

3

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.

Comments

3

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);

Comments

1

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;
}

Comments

0

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.

Comments

0

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".

Comments

0

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

Comments

-8
public string Serialize<T>(T settings)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
    StringWriter outStream = new StringWriter();
    serializer.Serialize(outStream, settings);
    return outStream.ToString();
}

3 Comments

This is how to serialize, not how to deserialize.
You just wrote code here. With no explanation, it's meaningless for many.
Code doesn't dispose of streams

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.