0

Using C#, is there a way to easily parse an XML file so that it can be used as an object?

Example XML:

<Config>
    <Ui>
        <Colour>black</Colour>
        <Size>small</Size>
    </Ui>
    <Output>
        <Mode>smb</Mode>
        <Version>2</Version>
    </Output>
</Config>

And then refer to the parameters in my application by

Config.Output.Mode

I've tried this method - How to Deserialize XML document

But when I try

var cfg = new Config();
cfg.Load(@"config.xml");
Console.WriteLine(cfg.Output.Mode);

visual studio indicates .Output.Mode is not valid.

Where Config.Load is

xmlData = File.ReadAllText(configPath);
    
var serializer = new XmlSerializer(typeof(Config));
    
using (var reader = new StringReader(xmlData))
{
    Config result = (Config)serializer.Deserialize(reader);
}
roapp
  • 530
  • 6
  • 17
Quantum_Kernel
  • 303
  • 1
  • 7
  • 19
  • 2
    *it doesn't work* - what it gives you? an error? null? could you post your code for reference? – Bagus Tesa Sep 26 '19 at 00:27
  • *"it doesn't work"* you have neither shown us your code, or error, i would consider reading the help on stack overflow. [ask] – TheGeneral Sep 26 '19 at 00:31
  • Can you share the exact error message you are getting from Visual studio? Also the code of Config, Output and Mode? – Chetan Sep 26 '19 at 00:36
  • Well, that's close, but what do you do with `result`? Because that's your deserialized `Config` object. Not `cfg`... – Heretic Monkey Sep 26 '19 at 00:37
  • "visual studio indicates .Output.Mode is not valid." - could you please clarify how that relates to XML or serialization? You may want to re-read [mcve] guidance and [edit] post to clarify. – Alexei Levenkov Sep 26 '19 at 01:11

2 Answers2

6

You have to create the classes that match the definition in the xml file in order to deserialize the file into an instance of the class. Note that I've named the properties with the same name as we have in the xml file. If you want to use different property names, then you'd need to add an attribute above the property that specifies the xml element that should map to it (like for the Ui, you would add the attribute: [XmlElement("Ui")]).

Note that I've also overridden the ToString methods for the classes so we can output them to the console in a nice fashion:

public class Config
{
    public UI Ui { get; set; }
    public Output Output { get; set; }

    public override string ToString()
    {
        return $"Config has properties:\n - Ui: {Ui}\n - Output: {Output}";
    }
}

public class UI
{
    public string Colour { get; set; }
    public string Size { get; set; }

    public override string ToString()
    {
        return $"(Colour: {Colour}, Size: {Size})";
    }
}

public class Output
{
    public string Mode { get; set; }
    public int Version { get; set; }

    public override string ToString()
    {
        return $"(Mode: {Mode}, Version: {Version})";
    }
}

Now all we have to do is create a StreamReader, point it to our file path, and then use the XmlSerializer class to Deserialize the file (casting the output to the appropriate type) into an object:

static void Main(string[] args)
{
    var filePath = @"f:\private\temp\temp2.txt";

    // Declare this outside the 'using' block so we can access it later
    Config config;

    using (var reader = new StreamReader(filePath))
    {
        config = (Config) new XmlSerializer(typeof(Config)).Deserialize(reader);
    }

    Console.WriteLine(config);

    GetKeyFromUser("\n\nDone! Press any key to exit...");
}

Output

enter image description here

Rufus L
  • 36,127
  • 5
  • 30
  • 43
4

Here are the classes:

public class Config
{
    public UI UI { get; set; }
    public Output Output { get; set; }
}

public struct UI
{
    public string Colour { get; set; }
    public string Size { get; set; }
}

public struct Output
{
    public string Mode { get; set; }
    public int Version { get; set; }
}

The Deserialize function:

    public static T Deserialize<T>(string xmlString)
    {
        if (xmlString == null) return default;
        var serializer = new XmlSerializer(typeof(T));
        using (var reader = new StringReader(xmlString))
        {
            return (T) serializer.Deserialize(reader);
        }
    }

And here's a working version:

        Config cfg = Deserialize<Config>(xmlString);
        Console.WriteLine(cfg.Output.Mode);          
Jacob Seleznev
  • 8,013
  • 3
  • 24
  • 34
  • 2
    What if I have more than one element? How could I deserialize this to that it could be referred to by cfg.Output[0].Mode ? – Quantum_Kernel Sep 26 '19 at 23:07