Creating class instances based on dynamic item lis

2020-05-09 12:13发布

问题:

I'm not sure if I could make my code cleaner by creating a separate class for the process I'm running but I'm doing it this way because it's how I know to do it.

My main objective is to create a JSON file from data collected through HtmlAgilityPack. I've been working with this problem the last couple days but I managed to figure out a way to do it. I managed to create a JSON file with the information retrieved but it didn't divide the information into separate objects in an object array. Instead it clustered up all the data as 1 object.

This was happening because I never created the objects with the parsed html data in the string list. Instead of creating separate lists and combining them, I need to create a list of objects made from the parsed html data and add them to a list.

To test out this hypothetical method I created 3 class instances and gave them values to see if the JSON file created the desired array of objects. When tested, it created the JSON array of objects as desired.

JSON Created:

[{"FavsGTS":"GT1","FavsGPICS":"GP1","FavsRNS":"RN1","FavsPIS":"PI1","FavsIsOns":"true"},
{"FavsGTS":"GT2","FavsGPICS":"GP2","FavsRNS":"RN2","FavsPIS":"PI2","FavsIsOns":"false"},
{"FavsGTS":"GT3","FavsGPICS":"GP3","FavsRNS":"RN3","FavsPIS":"PI3","FavsIsOns":"true"}]

Now I'm trying to figure out how can I dynamically create instances based out of the collected html data.

What I had in mind was doing something like:

gamertagsFav = new List<string>(FavsGTS.Count);
            gamertagsFav.AddRange(FavsGTS);

            foreach(string gamertagfav in gamertagsFav)
            {
                //creates a class instance and adds the parsed data in the same order.   
            }

An example of a generated instance would be as fallows:

gamerprofileFav gpfav1 = new gamerprofileFav()
            {
                FavsGTS = "gt1",
                FavsGPICS = "gpic1",
                FavsRNS = "rn1",
                FavsPIS = "pi1",
                FavsIsOns = "ison1"
            };

This is possible because all the parsed data is in the same order.

My code is a bit messy, but it is as fallows:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlAgilityPack;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
using System.IO;

namespace Parser_Test_1._0
{
    public partial class Form1 : Form
    {
        public List<string> FavsGTS { get; private set; }
        public List<string> FavsGPICS { get; private set; }
        public List<string> FavsRNS { get; private set; }
        public List<string> FavsPIS { get; private set; }
        public List<string> FavsIsOns { get; private set; }
        public List<string> allPlayers { get; private set; }
        public List<string> gamertagsFav { get; private set; }

        public Form1()
        {
            InitializeComponent();
        }

        public class gamerprofileFav
        {
            public string FavsGTS { get; set; }
            public string FavsGPICS { get; set; }
            public string FavsRNS { get; set; }
            public string FavsPIS { get; set; }
            public string FavsIsOns { get; set; }

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.Load(@"C:\Users\josec\Documents\Visual Studio 2015\Projects\THE XBOX PROJECT\Parser-Test-1.0\Parser-Test-1.0\bin\Debug\xbFrSourceCode.txt");

            string datacollected1 = doc.DocumentNode.SelectNodes("//*[@id=\"favoritesContent\"]/div[2]/div[2]/ul")[0].InnerHtml;
            string datacollected2 = doc.DocumentNode.SelectNodes("//*[@id=\"friendsContent\"]/div[2]/div[2]")[0].InnerHtml;
            label1.Text = datacollected1;
            label2.Text = datacollected2;

            //StreamWriter sw = new StreamWriter("datacollected1.txt");
            //sw.Write(datacollected1);
            //sw.Close();

            //Gamertags
            HtmlAgilityPack.HtmlDocument favs = new HtmlAgilityPack.HtmlDocument();
            favs.LoadHtml(datacollected1);

            FavsGTS = new List<string>();
            HtmlNodeCollection gts = favs.DocumentNode.SelectNodes("//li[@data-gamertag]");
            foreach (var gt in gts)
            {
                string datagamertag = gt.Attributes["data-gamertag"].Value;
                FavsGTS.Add(datagamertag);
            }

            listBox1.DataSource = FavsGTS;

            FavsGPICS = new List<string>();
            HtmlNodeCollection gpics = favs.DocumentNode.SelectNodes("//li/a[1]/img[1][@src]");
            foreach (var gpic in gpics)
            {
                string datagpic= gpic.Attributes["src"].Value;
                FavsGPICS.Add(datagpic);
            }

            listBox2.DataSource = FavsGPICS;

            FavsRNS = new List<string>();
            HtmlNodeCollection rns = favs.DocumentNode.SelectNodes("//li/div[2]/div[2]/div[1]/div[1]");
            foreach (var rn in rns)
            {
                string datarn = rn.InnerText;
                FavsRNS.Add(datarn);
            }

            listBox3.DataSource = FavsRNS;

            FavsPIS = new List<string>();
            HtmlNodeCollection pis = favs.DocumentNode.SelectNodes("//li/div[2]/div[2]/div[1]/div[2]");
            foreach (var pi in pis)
            {
                string datapi = pi.InnerText;
                FavsPIS.Add(datapi);
            }

            listBox4.DataSource = FavsPIS;

            FavsIsOns = new List<string>();
            HtmlNodeCollection isons = favs.DocumentNode.SelectNodes("//li[@data-isonline]");
            foreach (var ison in isons)
            {
                string dataison = ison.Attributes["data-isonline"].Value;
                FavsIsOns.Add(dataison);
            }

            listBox5.DataSource = FavsIsOns;
            //Test
            gamertagsFav = new List<string>(FavsGTS.Count);
            gamertagsFav.AddRange(FavsGTS);

            foreach(string gamertagfav in gamertagsFav)
            {

            }



            //Merge
            allPlayers = new List<string>(FavsGTS.Count + FavsGPICS.Count + FavsRNS.Count + FavsPIS.Count + FavsIsOns.Count);
            allPlayers.AddRange(FavsGTS);
            allPlayers.AddRange(FavsGPICS);
            allPlayers.AddRange(FavsRNS);
            allPlayers.AddRange(FavsPIS);
            allPlayers.AddRange(FavsIsOns);

            //GpsFav //+Start+
            gamerprofileFav gpfav1 = new gamerprofileFav()
            {
                FavsGTS = "GT1",
                FavsGPICS = "GP1",
                FavsRNS = "RN1",
                FavsPIS = "PI1",
                FavsIsOns = "true"
            };
            gamerprofileFav gpfav2 = new gamerprofileFav()
            {
                FavsGTS = "GT2",
                FavsGPICS = "GP2",
                FavsRNS = "RN2",
                FavsPIS = "PI2",
                FavsIsOns = "false"
            };
            gamerprofileFav gpfav3 = new gamerprofileFav()
            {
                FavsGTS = "GT3",
                FavsGPICS = "GP3",
                FavsRNS = "RN3",
                FavsPIS = "PI3",
                FavsIsOns = "true"
            };

            List<gamerprofileFav> gpfavs = new List<gamerprofileFav>();
            gpfavs.Add(gpfav1);
            gpfavs.Add(gpfav2);
            gpfavs.Add(gpfav3);
            //GgsFav //-END-

            listBox6.DataSource = allPlayers;
            listBox7.DataSource = gamertagsFav;

            //JSON Serialize
            //string data = JsonConvert.SerializeObject(gpfavs);
            //File.WriteAllText("data.json", data);
        }
        public class gpsFav
        {



        }

    }
}

This is the Form1 when run:

The data presented in the 5 small lists is the data that I wish to assign to the generated instances in the same order they appear. That way I can create a list based out of these generated instances which I can serialize to a JSON file.

回答1:

To avoid doing all of the hard work, there is already an option to deserialize a JSON object into a .NET object that you can work with, an example with your piece of code;

public class RootObject
{
    public string FavsGTS { get; set; }
    public string FavsGPICS { get; set; }
    public string FavsRNS { get; set; }
    public string FavsPIS { get; set; }
    public string FavsIsOns { get; set; }
}

While you simply deserialize it by;

RootObject gamertag_sample = JsonConvert.DeserializeObject<RootObject>(jsonstr);

Of course if you pass it an array of RootObject, you'll need to replace <RootObject> with <RootObject[]> and so on with the type.

As far as I understood this was the only problem you were seeking for a solution or have I missed something?

EDIT: With dynamic object you can create any value entry you wish, you'll need to go through a series of tasks to do so before however.

// this would contain your key,value for the generated instance.
// {example_key, "value"} would result later in myObject.example_key (returning "value")
var expandoObj = new ExpandoObject();
var eoCollection = (ICollection<KeyValuePair<string, object>>)expandoObj;
// add your key value pairs here
eoCollection.Add(new KeyValuePair<string, object>("example", "example value"));

dynamic myDynamicObject = expandoObj;
// myDynamicObject.example will return "example value", and would result in json:
//    "example":"example value"