Stefano Giovannelli
Stefano Giovannelli

Reputation: 11

Jsonconvert - How to define structure

Good evening. I have an XML structure like this:

string cRet = "<bands>";

cRet += "<artist>";

cRet += "<name>";
cRet += "Vasco";
cRet += "</name>";

cRet += "<lp>";
cRet += "<namelp>";
cRet += "Bollicine";
cRet += "</namelp>";
cRet += "<songs>";
cRet += "<song>";
cRet += "Bollicine";
cRet += "</song>";
cRet += "<song>";
cRet += "Vita Spericolata";
cRet += "</song>";
cRet += "<song>";
cRet += "Giocala";
cRet += "</song>";
cRet += "</songs>";
cRet += "</lp>";

cRet += "<lp>";
cRet += "<namelp>";
cRet += "Gli SPari Sopra";
cRet += "</namelp>";
cRet += "<songs>";
cRet += "<song>";
cRet += "Gli SPari Sopra";
cRet += "</song>";
cRet += "<song>";
cRet += "Gabri";
cRet += "</song>";
cRet += "<song>";
cRet += "Lo Show";
cRet += "</song>";
cRet += "</songs>";
cRet += "</lp>";

cRet += "</artist>";

cRet += "</bands>";


var serializer = new XmlSerializer(typeof(Root));
var root = (Root)serializer.Deserialize(new StringReader(cRet));
string cJson = JsonConvert.SerializeObject(root, Newtonsoft.Json.Formatting.Indented);

I define:

[XmlRoot("bands"), JsonObject]
public class Root
{
    [XmlElement, JsonProperty]
    public string name { get; set; }

    [XmlElement, JsonProperty]
    public string albumName { get; set; }

    [XmlElement, JsonProperty]
    public string song { get; set; }

}

I obtain:

{ "name": null, "albumName": null, "song": null }

If I use one level only I get perfect result. How can I define "artist" and "album"?

Upvotes: 0

Views: 66

Answers (1)

It all makes cents
It all makes cents

Reputation: 4991

Do you have Visual Studio 2017/2019? If so you can Generate Class From JSON or XML in Visual Studio . Once you have properly defined classes you should be able to use Newtonsoft.Json to create your json.

To create the classes from XML do the following:

Create your sample XML:

Note: If any element in your XML has multiple elements, ensure your sample data includes multiple elements.

<bands>
  <artist>
    <name>Vasco</name>
    <lp>
      <namelp>Bollicine</namelp>
      <songs>
        <song>Bollicine</song>
        <song>Vita Spericolata</song>
        <song>Giocala</song>
      </songs>
    </lp>
  </artist>
  <artist>
    <name>Other Artist</name>
    <lp>
      <namelp>Other Artist album name</namelp>
      <songs>
        <song>Song 1</song>
        <song>Song 2</song>
      </songs>
    </lp>
  </artist>
</bands>
  • Open Visual Studio 2017 (or 2019)

  • Create new Project (File => New Project => ...)

  • Add using statement: using System.Xml.Serialization;

  • Create new class (Project => Add Class...) name: bands

  • Open your sample XML in Notepad.

  • Highlight the XML, right-click, and select Copy

  • In VS menu, click Edit

  • Select Paste special

  • Select Paste XML As Classes

You'll get the following:

// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class bands
{

    private bandsArtist[] artistField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("artist")]
    public bandsArtist[] artist
    {
        get
        {
            return this.artistField;
        }
        set
        {
            this.artistField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class bandsArtist
{

    private string nameField;

    private bandsArtistLP lpField;

    /// <remarks/>
    public string name
    {
        get
        {
            return this.nameField;
        }
        set
        {
            this.nameField = value;
        }
    }

    /// <remarks/>
    public bandsArtistLP lp
    {
        get
        {
            return this.lpField;
        }
        set
        {
            this.lpField = value;
        }
    }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class bandsArtistLP
{

    private string namelpField;

    private string[] songsField;

    /// <remarks/>
    public string namelp
    {
        get
        {
            return this.namelpField;
        }
        set
        {
            this.namelpField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlArrayItemAttribute("song", IsNullable = false)]
    public string[] songs
    {
        get
        {
            return this.songsField;
        }
        set
        {
            this.songsField = value;
        }
    }
}

I modified/refactored the code a little bit and ended up with the code below. I changed the case of the class names. Also, to order elements of the same depth in the desired order, I added interfaces for some of the classes (as described in .NET Serialization Ordering)

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false, ElementName = "bands")]
public partial class Bands
{

    [System.Xml.Serialization.XmlElementAttribute("artist")]
    public List<BandsArtist> artist { get; set; } = new List<BandsArtist>(); 
}

public interface IBandsArtist
{
    string name { get; set; }
    List<BandsArtistLP> lp { get; set; }

}

[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class BandsArtist : IBandsArtist
{
    [XmlElement("name")]
    public string name { get; set; }


    [System.Xml.Serialization.XmlElementAttribute("lp")]
    public List<BandsArtistLP> lp { get; set; } = new List<BandsArtistLP>();
    
}

public interface IBandsArtistLP
{
    string namelp { get; set; }
    List<string> songs { get; set; }
}

[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class BandsArtistLP : IBandsArtistLP
{

    [XmlElement("namelp")]
    public string namelp { get; set; }

    [XmlArrayItemAttribute("song", IsNullable = false)]
    public List<string> songs { get; set; } = new List<string>();
    
}

Use Newtonsoft.json to serialize the "bands" class (where "myBands" is an instance of class "bands" that contains your data)

string cJson = JsonConvert.SerializeObject(myBands, Newtonsoft.Json.Formatting.Indented);

The resulting json is:

{
  "artist": [
    {
      "name": "Vasco",
      "lp": [
        {
          "namelp": "Bollicine",
          "songs": [
            "Bollicine",
            "Vita Spericolata",
            "Giocala"
          ]
        }
      ]
    },
    {
      "name": "Other Artist",
      "lp": [
        {
          "namelp": "Other Artist album name",
          "songs": [
            "Song 1",
            "Song 2"
          ]
        }
      ]
    }
  ]
}

Upvotes: 1

Related Questions