Results 1 to 7 of 7

Thread: Deserialize XML to Object - Main Property Names are in the XML Element

  1. #1
    .NET Framework
    .NET 4.5
    Join Date
    Oct 2018
    Posts
    4
    Rep Power
    0

    Deserialize XML to Object - Main Property Names are in the XML Element

    Hi. I am having an issue figuring out the best way to deserialize the below XML into an easily usable object. Using a C# to XML converter I have a usable object in which I can serialize and deserialize objects. The issue is that using this XML I have to use LINQ to pull out property values. The main property names I am after are stored in an XML element called Name. Deserializing the XML will give me a list of Settings. The setting contains 2 properties, name & value; LINQ is the only way I know to get the values.

    I have a wrapper class that takes the deserialized object and has a property for each of the 'Setting' property in the XML. The getter/setter for properties in the wrapper contains the LINQ required. There has to be a better way to do this right?

    Wrapper object with only the property Description.

    Code:
    public class ObjectWrapper{    public string Description
        {
            get
            {
                var result = "";
    
                try
                {
                    if (obj is null) return result;
    
                    var columns = obj.Setting.Where(q => q.Name == "Description").ToList();
    
                    if (columns.Count == 1)
                        result = columns.Single().Value.ToString();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("Failed to parse Description obj. Ex: " + ex.ToString());
                }
    
                return result;
            }
            set
            {
                if (string.IsNullOrEmpty(value)) return;
    
                try
                {
                    if (obj is null) return;
    
                    var columns = obj.Setting.Where(q => q.Name == "Description").ToList();
    
                    if (columns.Count == 1)
                        columns.Single().Value = value;
                    else
                    {
                        //if Name doesn't exist, create it and assign it.
                        var Name = new Setting
                        {
                            Name = "Description",
                            Value = value
                        };
    
                        obj.Setting.Add(Name);
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("Failed to parse Description obj. Ex: " + ex.ToString());
                }
            }
        }
    }

    XML

    Code:
    <Object>
      <Processor>
        <Pages>
          <Page>
            <Name>Settings</Name>
            <Row>
              <Setting>
                <Name>Enable</Name>
                <Value>True</Value>
              </Setting>
              <Setting>
                <Name>Name</Name>
                <Value>value</Value>
              </Setting>
              <Setting>
                <Name>Description</Name>
                <Value>value</Value>
              </Setting>
            </Row>
            <Row>
              <Setting>
                <Name>Enable</Name>
                <Value>True</Value>
              </Setting>
              <Setting>
                <Name>Name</Name>
                <Value>value</Value>
              </Setting>
              <Setting>
                <Name>Description</Name>
                <Value>value</Value>
              </Setting>
            </Row>
          </Page>
        </Pages>
      </Processor>
    </Object>



    Plugged the above code into this site to generate XML: https://xmltocsharp.azurewebsites.net/


    Code:
    /*     Licensed under the Apache License, Version 2.0
        
    http://www.apache.org/licenses/LICENSE-2.0
    */
    using System;
    using System.Xml.Serialization;
    using System.Collections.Generic;
    namespace Xml2CSharp
    {
        [XmlRoot(ElementName="Setting")]
        public class Setting {
            [XmlElement(ElementName="Name")]
            public string Name { get; set; }
            [XmlElement(ElementName="Value")]
            public string Value { get; set; }
        }
    
        [XmlRoot(ElementName="Row")]
        public class Row {
            [XmlElement(ElementName="Setting")]
            public List<Setting> Setting { get; set; }
        }
    
        [XmlRoot(ElementName="Page")]
        public class Page {
            [XmlElement(ElementName="Name")]
            public string Name { get; set; }
            [XmlElement(ElementName="Row")]
            public List<Row> Row { get; set; }
        }
    
        [XmlRoot(ElementName="Pages")]
        public class Pages {
            [XmlElement(ElementName="Page")]
            public Page Page { get; set; }
        }
    
        [XmlRoot(ElementName="Processor")]
        public class Processor {
            [XmlElement(ElementName="Pages")]
            public Pages Pages { get; set; }
        }
    
        [XmlRoot(ElementName="Object")]
        public class Object {
            [XmlElement(ElementName="Processor")]
            public Processor Processor { get; set; }
        }
    }
    Last edited by jmooney5115; 10-17-2018 at 10:59 AM.

  2. #2
    .NET Framework
    .NET 4.5
    Join Date
    Apr 2011
    Location
    Norway
    Posts
    431
    Rep Power
    109
    You can paste the xml here Xml2CSharp.com | Convert your XML Examples into XmlSerializer compatable C# Classes as you said and copy the generated classes to a new Code File (empty .cs file).
    Note that it need accurate xml data to generate collection properties, for example if the xml has multiple Page objects the sample file needs that too for the converter to see it. Here the sample has a single Page object and that is converted to a single item property.

    Then you can deserialize the xml like in this example: How to: Read Object Data from an XML File (C#) | Microsoft Docs for type Xml2CSharp.Object.

    Now you can loop through the rows and settings:
    foreach (var row in overview.Processor.Pages.Page.Row)
    {
    foreach (var setting in row.Setting)
    {
    //setting.Name
    //setting.Value
    }
    }

    I used the 'overview' variable name from the deserialization example for easier reference.

    There also exist a .Net tool called xsd.exe that can do similar, but it may not work out of the box and may generate far more complicated schema/classes. This is also the same as 'Paste Xml As Classes' option in VS. I can reveal that for your sample xml it generated just a mess in my opinion.
    [xcode=c#] code here [/xcode] - see bbcode list or use formatting buttons in posting editor.

    Visual Studio Community 2017

  3. #3
    .NET Framework
    .NET 4.5
    Join Date
    Oct 2018
    Posts
    4
    Rep Power
    0
    Thanks for the reply. You have given me an idea here that I can iterate through each row/setting and use reflection to get property values. This should work better than hundreds of lines of LINQ to get property values.


    I'm inheriting a project and I believe they used xsd.exe to generate the C# from XML. You're right that it generated FAR more complicated classes.

  4. #4
    .NET Framework
    .NET 4.5
    Join Date
    Apr 2011
    Location
    Norway
    Posts
    431
    Rep Power
    109
    Why use reflection? That's typically used when you have string with a property name and want to get the PropertyInfo and its value from an object dynamically, here you have an object with these known properties already.
    [xcode=c#] code here [/xcode] - see bbcode list or use formatting buttons in posting editor.

    Visual Studio Community 2017

  5. #5
    .NET Framework
    .NET 4.5
    Join Date
    Oct 2018
    Posts
    4
    Rep Power
    0
    Quote Originally Posted by JohnH View Post
    Why use reflection? That's typically used when you have string with a property name and want to get the PropertyInfo and its value from an object dynamically, here you have an object with these known properties already.

    Maybe I'm missing something. The code doesn't know to split out the properties (Enable, Name, & Description) that exist as a Setting in each row. Each row contains many settings. The setting contains the property name and the value of the property.

    I created a sample project to illustrate how this looks. https://github.com/jmooney5115/funkyXmlSerialization





    What I want:

    • Object
      • Processor
        • Pages
          • Page
            • Row
              • string Enabled
              • string Name
              • string Description


    What I get:
    • Object
      • Processor
        • Pages
          • Page
            • Row
              • Setting
                • string Name = Enabled
                • string Value = True

              • Setting
                • string Name = Name
                • string Value = jmooney

              • Setting
                • string Name = Description
                • string Value = user on csharpforums.net



  6. #6
    .NET Framework
    .NET 4.5
    Join Date
    Apr 2011
    Location
    Norway
    Posts
    431
    Rep Power
    109
    I see. That is the problem of the xml structure, not the code. To get "what you want" without work the xml data should have been like this:
    HTML Code:
            <Row>
                <Enable>True</Enable>
                <Name>value</Name>
                <Description>value</Description>
            </Row>
    Otherwise you have to read the xml file and manually create the objects of your own defined classes. For example let's say you only wanted the rows and defined this class:
    public class Row
    {
    public string Enable { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    }

    'Enable' looks like it should be a boolean by the way.

    Then you read the xml and create the objects:
    var doc = XDocument.Load(@"d:\sample.xml");
    var rows = new List<Row>();
    foreach (var row in doc.Descendants("Row"))
    {
    var row = new Row();
    foreach (var setting in row.Elements("Setting"))
    {
    var name = setting.Element("Name").Value;
    var value = setting.Element("Value").Value;
    row.GetType().GetProperty(name).SetValue(row, value);
    }
    rows.Add(row);
    }

    Here I used reflection in just one line, but could have used a switch statement for different handling of each property, for example to set row.Enable = Convert.ToBoolean(value);
    [xcode=c#] code here [/xcode] - see bbcode list or use formatting buttons in posting editor.

    Visual Studio Community 2017

  7. #7
    .NET Framework
    .NET 4.5
    Join Date
    Oct 2018
    Posts
    4
    Rep Power
    0
    Thank you for the detailed reply. I should have mentioned I'm dealing with 3rd party XML which I cannot modify. It sounds like I need to keep doing what I'm doing.

Similar Threads

  1. Online XML Object Viewer
    By jvpsolutions in forum XML
    Replies: 0
    Last Post: 02-20-2017, 9:16 PM
  2. Replies: 0
    Last Post: 08-19-2016, 7:45 PM
  3. LINQ Expression: Accessing The Field/Property Of A Sub-Object
    By dipique in forum C# General Discussion
    Replies: 0
    Last Post: 02-09-2016, 6:45 PM
  4. Using custom object to map to entity property
    By Contissi in forum Console Application
    Replies: 1
    Last Post: 12-02-2014, 7:19 PM
  5. Question Change XML element
    By Ice in forum XML
    Replies: 1
    Last Post: 01-25-2013, 7:30 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •