XML XElement and loops - c#

Please help me to fix the piece of code that results in this xml output.
The elements called "Frequency" and "ScheduleType" are all being stuck under the first element of schedule. How do I fix this?
I'm reading data from a CSV type file and then based on the position and value I add the relevant data (or converted values) to the relevant XML values.
You'll see that I use the suggested method where possible but as I have to use an additional CASE statement I get stuck so I revert to using the LAST statement to try and find the correct element to continue from.
<Schedules>
<Schedule Number="1">
<ScheduleName>Cumulative</ScheduleName>
<BackupType>Cinc</BackupType>
<Multiplexing>4</Multiplexing>
<RetentionLevel>infinite</RetentionLevel>
<ResidenceIsSLP>No</ResidenceIsSLP>
<MultipleCopies>No</MultipleCopies>
<ScheduleType />
<Frequency>
<Count>5</Count>
<Unit>Days</Unit>
<Count>2</Count>
<Unit>Weeks</Unit>
<Count>1</Count>
<Unit>Days</Unit>
</Frequency>
<ScheduleType />
<Frequency />
<ScheduleType />
<Frequency />
</Schedule>
<Schedule Number="2">
<ScheduleName>Full</ScheduleName>
<BackupType>Full</BackupType>
<Multiplexing>4</Multiplexing>
<RetentionLevel>infinite</RetentionLevel>
<ResidenceIsSLP>No</ResidenceIsSLP>
<MultipleCopies>No</MultipleCopies>
</Schedule>
<Schedule Number="3">
<ScheduleName>Differential</ScheduleName>
<BackupType>Diff</BackupType>
<Multiplexing>4</Multiplexing>
<RetentionLevel>2 weeks</RetentionLevel>
<ResidenceIsSLP>No</ResidenceIsSLP>
<MultipleCopies>No</MultipleCopies>
</Schedule>
</Schedules>
public XDocument PolicyAttributesSection()
{
XDocument policies = XDocument.Load("C:\\Output Files\\testnbu.xml");
policies.Element("NBUConfig").Add(new XElement("Policies"));
using (TextFieldParser policy = new TextFieldParser("C:\\Input Files\\RAM\\bppllist.txt"))
{
string[] ignoreLines1 = { "NAMES", "KEY", "RCMD", "BCMD", "FOE", "SHAREGROUP", "APPLICATIONDEFINED", "SCHEDFOE" };
policy.TextFieldType = FieldType.Delimited;
policy.Delimiters = new string[] { " ", ",", ";" };
policy.HasFieldsEnclosedInQuotes = true;
policy.CommentTokens = ignoreLines1;
policy.TrimWhiteSpace = true;
string[] policyprops;
int schedulenumber;
while (!policy.EndOfData)
{
schedulenumber = 0;
var pl = policies.Element("NBUConfig").Element("Policies").Elements("Policy");
policyprops = policy.ReadFields();
switch (policyprops[0])
{
case "SCHED":
schedulenumber++;
int scheduletypenumber;
bool schedparsed = int.TryParse((policyprops[2]), out scheduletypenumber);
string scheduletypename = ScheduleType_Lookup[(scheduletypenumber)];
int retlevel;
bool retparsed = int.TryParse((policyprops[5]), out retlevel);
string retentionperiod = (Retention_Lookup[(retlevel)]).ToString();
int isslp;
bool isslpparsed = int.TryParse((policyprops[17]), out isslp);
int copynumber;
bool copynumberparsed = int.TryParse((policyprops[12]), out copynumber);
if (copynumber > 0)
{
copynumber = 1;
}
pl.Last().Element("Schedules").Add(new XElement(("Schedule"), new XAttribute("Number", (schedulenumber)),
(new XElement("ScheduleName", policyprops[1])),
(new XElement("BackupType", (scheduletypename))),
(new XElement("Multiplexing", policyprops[3])),
(new XElement("RetentionLevel", (retentionperiod))),
(new XElement("ResidenceIsSLP", (yesno_lookup[(isslp)]))),
(new XElement("MultipleCopies", (yesno_lookup[(copynumber)])))));
pl.Last().Element("Schedules").Element("Schedule").Add(new XElement(("ScheduleType")));
switch (policyprops[11])
{
case "1":
pl.Last().Element("Schedules").Element("Schedule").Add(new XElement("Calendar", "Enabled"));
pl.Last().Element("Schedules").Element("Schedule").Add
(new XElement("CalendarRetries", "Disabled"));
break;
case "2":
pl.Last().Element("Schedules").Element("Schedule").Add
(new XElement("Calendar", "Enabled"));
pl.Last().Element("Schedules").Element("Schedule").Add
(new XElement("CalendarRetries", "Enabled"));
break;
case "0":
int freqseconds;
bool startparsed = int.TryParse((policyprops[4]), out freqseconds);
var freq = frequency(freqseconds);
pl.Last().Element("Schedules").Element("Schedule").Add
(new XElement("Frequency"));
int count = freq.Item1;
string unit = freq.Item2;
pl.Last().Element("Schedules").Element("Schedule").Element("Frequency").Add
(new XElement("Count", (count).ToString()));
pl.Last().Element("Schedules").Element("Schedule").Element("Frequency").Add
(new XElement("Unit", (unit)));
break;
}
break;
}
}
policies.Save("C:\\Output Files\\testnbu.xml");
return policies;

This statement is the problem:
test.Element("NBUConfig")
.Element("Policies")
.Elements("Policy").Last()
.Elements("Schedules").Last()
.Element("Schedule")
.Add(new XElement(("SchedulesStuff"), (scount)));
You're adding the SchedulesStuff to the first Schedule element within the last Schedules element... instead of adding it to the last Schedule element within the only Schedules element.
All of this code would be much, much simpler - and less error-prone - if you had far less repetitive code. So consider instead:
var policies = new XElement("Policies");
var test = new XDocument(new XElement("NBUConfig", policies));
// Hint: for loops are more idiomatic than while loops here
for (int pcount = 0; pcount < 3; pcount++)
{
var schedules = new XElement("Schedules");
for (int scount = 0; scount < 3; scount++)
{
schedules.Add(new XElement("Schedule",
new XAttribute("Number", scount),
new XElement("ScheduleStuff", scount));
}
policies.Add(new XElement("Policy",
new XElement("PolicyName", pcount),
new XElement("General"),
new XElement("Clients"),
new XElement("IncludeList"),
schedules));
}

Related

How can I access multi-element List data stored in a public class?

My first question on SO:
I created this public class, so that I can store three elements in a list:
public class myMultiElementList
{
public string Role {get;set;}
public string Country {get;set;}
public int Commonality {get;set;}
}
In my main class, I then created a new list using this process:
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
I've added data to EmployeeRolesCountry and have validated that has 472 lines. However, when I try to retrieve it as below, my ForEach loop only retrieves the final line added to the list, 472 times...
foreach (myMultiElementList tmpClass in EmployeeRolesCountry)
{
string d1Value = tmpClass.Role;
Console.WriteLine(d1Value);
string d2Value = tmpClass.Role;
Console.WriteLine(d2Value);
int d3Value = tmpClass.Commonality;
Console.WriteLine(d3Value);
}
This was the most promising of the potential solutions I found on here, so any pointers greatly appreciated.
EDIT: adding data to EmployeeRolesCountry
/*
Before this starts, data is taken in via a csvReader function and parsed
All of the process below is concerned with two fields in the csv
One is simply the Country. No processing necessary
The other is bio, and this itself needs to be parsed and cleansed several times to take roles out
To keep things making sense, I've taken much of the cleansing out
*/
private void File_upload_Click(object sender, EventArgs e)
{
int pos = 0;
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
int a = 0;
delimiter = ".";
string token;
foreach (var line in records.Take(100))
{
var fields = line.ToList();
string bio = fields[5];
string country = fields[4];
int role_count = Regex.Matches(bio, delimiter).Count;
a = bio.Length;
for (var i = 0; i < role_count; i++)
{
//here I take first role, by parsing on delimiter, then push back EmployeeRolesCountry with result
pos = bio.IndexOf('.');
if (pos != -1)
{
token = bio.Substring(0, pos);
string original_token = token;
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
a = original_token.Length;
bio = bio.Remove(0, a + 1);
}
}
}
}
EDIT:
When grouped by multiple properties, this is how we iterate through the grouped items:
var employeesGroupedByRolwAndCountry = EmployeeRolesCountry.GroupBy(x => new { x.Role, x.Country });
employeesGroupedByRolwAndCountry.ToList().ForEach
(
(countryAndRole) =>
{
Console.WriteLine("Group {0}/{1}", countryAndRole.Key.Country, countryAndRole.Key.Role);
countryAndRole.ToList().ForEach
(
(multiElement) => Console.WriteLine(" : {0}", multiElement.Commonality)
);
}
);
__ ORIGINAL POST __
You are instantiating rc1 only once (outside the loop) and add the same instance to the list.
Please make sure that you do
var rc1 = new myMultiElementList();
inside the loop where you are adding the elements, and not outside.
All references are the same in your case:
var obj = new myObj();
for(i = 0; i < 5; i++)
{
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
now the list has 5 elements, all pointing to the obj (the same instance, the same object in memory), and when you do
obj.Prop1 = "Prop" + 5
you update the same memory address, and all the pointers in the list points to the same instance so, you are not getting 472 copies of the LAST item, but getting the same instance 472 times.
The solution is simple. Create a new instance every time you add to your list:
for(i = 0; i < 5; i++)
{
var obj = new myObj();
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
Hope this helps.

Got NullReferenceException When I use same code but different expression

I'm writing a project about game's character data.
And each character in the data document have four types, Lv1 and LvMAX, and HP, STR, VIT, INT, MEN.
I use top one code at the middle part and got NullReferenceException when I use it to get some data like:
int x = CD.Parameters.Basic.Awaked.Force.Lv1.STR;
Force will be null. But when I use buttom one at the middle part, Force won't be null.
What's the difference between that two?
Code below
public class ParamType
{
public ParamLv Mebius, Force, Aegis, Magius;
string cost;
DataRow[] Datas;
List<int> ToMebius = new List<int>(), ToForce = new List<int>(), ToAegis = new List<int>(), ToMagius = new List<int>(); //HP, HP, STR, STR, VIT, VIT, INT, INT, MEN, MEN
public ParamType(SData Data, bool awaked)
{
if (awaked)
{
Data.CharaID = CharaCOM.AwakedID(Data.CharaID);
}
Datas = DataCOM.Search(Data.CharaID, Data.DTs.Source, Data.TitleP.Start[(int)DataTitle.CharacterParams], Const.COL_CHARACTER_ID, Const.COL_CHARACTER_ID);
cost = DataCOM.Search(Data.DTs.Source, Data.CharaID, Const.COL_COST, 0, Data.TitleP.Start[(int)DataTitle.CharacterParams], Const.COL_CHARACTER_ID_WITH_TYPE);
List<int>[] SArray = { ToMebius, ToForce, ToAegis, ToMagius };
for (int i = 0; i < Datas.Length; i++)
{
SArray[i] = new List<int>();
for (int j = Const.COL_PARAM_MIN; j < Const.COL_PARAM_MIN + Const.COL_PARAM_LENGTH; j++)
{
SArray[i].Add(Convert.ToInt32(Datas[i][j]));
}
}
/*
this will send NullReference Exception
ParamLv[] PLArray = new ParamLv[4];
for (int i = 0; i < SArray.Length; i++)
{
PLArray[i] = new ParamLv(Data, SArray[i]);
}
*/
/*
This won't get exception and I can get correct data I want.
Mebius = new ParamLv(Data, SArray[0]);
Force = new ParamLv(Data, SArray[1]);
Aegis = new ParamLv(Data, SArray[2]);
Magius = new ParamLv(Data, SArray[3]);
*/
}
public class ParamLv
{
public Params Lv1, LvMax;
List<int> ToLv1 = new List<int>(), ToLvMAX = new List<int>(); //HP, STR, VIT, INT, MEN
public ParamLv(SData Data, List<int> ParamsL)
{
for (int i = 0; i < ParamsL.Count; i += Const.COL_PARAM_MIN_MAX_GAP)
{
ToLv1.Add(ParamsL[i]);
ToLvMAX.Add(ParamsL[i + 1]);
}
Lv1 = new Params(Data, ToLv1);
LvMax = new Params(Data, ToLvMAX);
}
public class Params
{
//some method and properties to get or set Parameters.
}
}
Please tell me if something still bad, and this is my first time to ask question here, so If I did something wrong, please tell me. Thanks for #MicroVirus , #Moriarty and #mvikhona told my mistake.
Mebius = new ParamLv(Data, SArray[0]);
Force = new ParamLv(Data, SArray[1]);
Aegis = new ParamLv(Data, SArray[2]);
Magius = new ParamLv(Data, SArray[3]);
This works, because you are assigning reference to new ParamLv to your properties.
But in this case:
ParamLv[] PLArray = { Mebius, Force, Aegis, Magius };
for (int i = 0; i < PLArray.Length; i++)
{
PLArray[i] = new ParamLv(Data, SArray[i]);
}
you aren't filling your array with variables/properties themselves, but you are filling it with references your properties hold, in the end your array will hold reference to 4 new ParamLw, but your property Force will stay null.
Edit:
I'll try to explain it a bit different. Let's say you have this code:
ParamLv[] PLArray = { Force };
At this moment value of PLArray[0] is same as value of Force, but PLArray[0] isn't Force.
The moment you do this:
PLArray[0] = new ParamLv(Data, null);
new ParamLv(Data, null) returns reference to new ParamLv and you assign this to your PLArray[0], but like I said before PLArray[0] isn't Force, so Force will stay unchanged.
If that didn't explain it well, try to look at this piece of code, it does what you are trying to do.
int a = 1;
int[] myArr = { a }; // a = 1, myArr[0] = 1
myArr[0] = 2; // a = 1, myArr[0] = 2
object obj = null;
object[] objArr = { obj }; // obj = null, objArr[0] = null
objArr[0] = new object(); // obj = null, objArr[0] = 'reference to new object'

Making var 's in a for-loop

It is hard to explain but I will show an example of what I want in my code:
At the moment I do it this way:
var something1 = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
var something2 = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
var something3 = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
something1.Name = "sheet1";
something2.Name = "sheet2";
something3.Name = "sheet3";
I want to do the making of those var's in a for-loop
This is what I thought it should be:
for (int i=1;i<4;i++)
{
var ("something" +i) = new Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet); // this (of course) doenst work
}
Any ideas on how to do this?
I tried this, but it didn't work:
var something = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1 , XlSheetType.xlWorksheet)[4];
you can use a dictionary
var somethigs = new Dictionary<int, xxx.ApplicationClass>();
for (var i = 1; i < 4; i++)
{
somethigs[i] = new xxx.ApplicationClass();
}
//access them like this
somethigs[1].Name = "sheet1";
somethigs[2].Name = "sheet2";
or use an array like this
var somethigs = new xxx.ApplicationClass[4];
for (var i = 0; i < 4; i++)
{
somethigs[i] = new xxx.ApplicationClass();
}
somethigs[0].Name = "sheet1";
somethigs[1].Name = "sheet2";
keep in mind that arrays have zero based indexes.
If you know for sure, the amount of instances you will need, creating an array or list of class instances will do what you are after.
If you want something more sophisticated, you could also create a dictionary in which you provide names to each of your class instances, this could provide you with an access by name sort of thing mechanism.
Dictionary<string, ApplicationClass> dictionary = new Dictionary<string, ApplicationClass>();
for(int i = 0; i < 4; i++) {
dictionary.Add("something" + i, new xxx.ApplicationClass());
}
var myApplicationClass = dictionary["something1"];
You should use an array. In your particular case,
var something = new xxx.ApplicationClass[4];
for (int i = 0; i < 3; i++)
{
something[i] = new (Microsoft.Office.Interop.Excel.Worksheet)appExcel.Worksheets.Add(Type.Missing, appExcel.Worksheets[appExcel.Worksheets.Count], 1, XlSheetType.xlWorksheet);
something[i].Name = "sheet" + (i + 1).ToString();
}
You should probably look for more information about what arrays an how they work. See for example https://msdn.microsoft.com/en-us/library/aa288453%28v=vs.71%29.aspx

Get the positions of unique elements in a string[]

I have an xml file that I am accessing to create a report of time spent on a project. I'm returning the unique dates to a label created dynamically on a winform and would like to compile the time spent on a project for each unique date. I have been able to return all of the projects under each date or only one project. Currently I'm stuck on only returning one project. Can anyone please help me?? This is what the data should look like if it's correct.
04/11/15
26820 2.25
27111 8.00
04/12/15
26820 8.00
04/13/15
01det 4.33
26820 1.33
27225 4.25
etc.
This is how I'm retrieving the data
string[] weekDateString = elementDateWeekstring();
string[] uniqueDates = null;
string[] weeklyJobNumber = elementJobNumWeek();
string[] weeklyTicks = elementTicksWeek();
This is how I'm getting the unique dates.
IEnumerable<string> distinctWeekDateIE = weekDateString.Distinct();
foreach (string d in distinctWeekDateIE)
{
uniqueDates = distinctWeekDateIE.ToArray();
}
And this is how I'm creating the labels.
try
{
int dateCount;
dateCount = uniqueDates.Length;
Label[] lblDate = new Label[dateCount];
int htDate = 1;
int padDate = 10;
for (int i = 0; i < dateCount; i++ )
{
lblDate[i] = new Label();
lblDate[i].Name = uniqueDates[i].Trim('\r');
lblDate[i].Text = uniqueDates[i];
lblDate[i].TabIndex = i;
lblDate[i].Bounds = new Rectangle(18, 275 + padDate + htDate, 75, 22);
targetForm.Controls.Add(lblDate[i]);
htDate += 22;
foreach (string x in uniqueDates)
{
int[] posJobNumber;
posJobNumber = weekDateString.Select((b, a) => b == uniqueDates[i].ToString() ? a : -1).Where(a => a != -1).ToArray();
for (int pjn = 0; pjn < posJobNumber.Length; pjn++)
{
if (x.Equals(lblDate[i].Text))
{
Label lblJobNum = new Label();
int htJobNum = 1;
int padJobNum = 10;
lblJobNum.Name = weeklyJobNumber[i];
lblJobNum.Text = weeklyJobNumber[i];
lblJobNum.Bounds = new Rectangle(100, 295 + padJobNum + htJobNum, 75, 22);
targetForm.Controls.Add(lblJobNum);
htJobNum += 22;
htDate += 22;
padJobNum += 22;
}
}
}
}
}
I've been stuck on this for about 3 months. Is there anyone that can describe to me why I'm not able to properly retrieve the job numbers that are associated with a particular date. I don't believe that these are specifically being returned as dates. Just a string that looks like a date.
I really appreciate any help I can get. I'm just completely baffled. Thank you for any responses in advance. I truly appreciate the assistance.
EDIT: #Sayka - Here is the xml sample.
<?xml version="1.0" encoding="utf-8"?>
<Form1>
<Name Key="4/21/2014 6:51:17 AM">
<Date>4/21/2014</Date>
<JobNum>26820</JobNum>
<RevNum>00000</RevNum>
<Task>Modeling Secondary</Task>
<Start>06:51 AM</Start>
<End>04:27 PM</End>
<TotalTime>345945089017</TotalTime>
</Name>
<Name Key="4/22/2014 5:44:22 AM">
<Date>4/22/2014</Date>
<JobNum>26820</JobNum>
<RevNum>00000</RevNum>
<Task>Modeling Secondary</Task>
<Start>05:44 AM</Start>
<End>06:56 AM</End>
<TotalTime>43514201221</TotalTime>
</Name>
<Name Key="4/22/2014 6:57:02 AM">
<Date>4/22/2014</Date>
<JobNum>02e-n-g</JobNum>
<RevNum>00000</RevNum>
<Task>NET Eng</Task>
<Start>06:57 AM</Start>
<End>07:16 AM</End>
<TotalTime>11706118875</TotalTime>
</Name>
....
</Form1>
This is how I'm getting the information out of the xml file and returning a string[].
public static string[] elementDateWeekstring()
{
//string datetxtWeek = "";
XmlDocument xmldoc = new XmlDocument();
fileExistsWeek(xmldoc);
XmlNodeList nodeDate = xmldoc.GetElementsByTagName("Date");
int countTicks = 0;
string[] dateTxtWeek = new string[nodeDate.Count];
for (int i = 0; i < nodeDate.Count; i++)
{
dateTxtWeek[i] = nodeDate[i].InnerText;
countTicks++;
}
return dateTxtWeek;
}
Job number and Ticks are returned in a similar fashion. I've been able to reuse these snippets throught out the code. This is a one dimensional xml file?? It will always return a position for a jobnumber that equates to a date or Ticks. I will never have more or less of any one element.
You can use Linq-to-XML to parse the XML file, and then use Linq-to-objects to group (and order) the data by job date and order each group by job name.
The code to parse the XML file is like so:
var doc = XDocument.Load(filename);
var jobs = doc.Descendants("Name");
// Extract the date, job number, and total time from each "Name" element.:
var data = jobs.Select(job => new
{
Date = (DateTime)job.Element("Date"),
Number = (string)job.Element("JobNum"),
Duration = TimeSpan.FromTicks((long)job.Element("TotalTime"))
});
The code to group and order the jobs by date and order the groups by job name is:
var result =
data.GroupBy(job => job.Date).OrderBy(g => g.Key)
.Select(g => new
{
Date = g.Key,
Jobs = g.OrderBy(item => item.Number)
});
Then you can access the data by iterating over each group in result and then iterate over each job in the group, like so:
foreach (var jobsOnDate in result)
{
Console.WriteLine("{0:d}", jobsOnDate.Date);
foreach (var job in jobsOnDate.Jobs)
Console.WriteLine(" {0} {1:hh\\:mm}", job.Number, job.Duration);
}
Putting this all together in a sample compilable console application (substitute the filename for the XML file as appropriate):
using System;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApplication2
{
class Program
{
private static void Main()
{
string filename = #"d:\test\test.xml"; // Substitute your own filename here.
// Open XML file and get a collection of each "Name" element.
var doc = XDocument.Load(filename);
var jobs = doc.Descendants("Name");
// Extract the date, job number, and total time from each "Name" element.:
var data = jobs.Select(job => new
{
Date = (DateTime)job.Element("Date"),
Number = (string)job.Element("JobNum"),
Duration = TimeSpan.FromTicks((long)job.Element("TotalTime"))
});
// Group the jobs by date, and order the groups by job name:
var result =
data.GroupBy(job => job.Date).OrderBy(g => g.Key)
.Select(g => new
{
Date = g.Key,
Jobs = g.OrderBy(item => item.Number)
});
// Print out the results:
foreach (var jobsOnDate in result)
{
Console.WriteLine("{0:d}", jobsOnDate.Date);
foreach (var job in jobsOnDate.Jobs)
Console.WriteLine(" {0} {1:hh\\:mm}", job.Number, job.Duration);
}
}
}
}
The output is like this
Create a new project
Set form size bigger.
Apply these codes.
Set the location for your XML file.
Namespaces
using System.Xml;
using System.IO;
Form Code
public partial class Form1 : Form
{
const string XML_FILE_NAME = "D:\\emps.txt";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
prepareDataGrid();
List<JOBS> jobsList = prepareXML(XML_FILE_NAME);
for (int i = 0; i < jobsList.Count; i++)
{
addDateRow(jobsList[i].jobDate.ToString("M'/'d'/'yyyy"));
for (int j = 0; j < jobsList[i].jobDetailsList.Count; j++)
dgv.Rows.Add(new string[] {
jobsList[i].jobDetailsList[j].JobNumber,
jobsList[i].jobDetailsList[j].JobHours
});
}
}
DataGridView dgv;
void prepareDataGrid()
{
dgv = new DataGridView();
dgv.BackgroundColor = Color.White;
dgv.GridColor = Color.White;
dgv.DefaultCellStyle.SelectionBackColor = Color.White;
dgv.DefaultCellStyle.SelectionForeColor = Color.Black;
dgv.DefaultCellStyle.ForeColor = Color.Black;
dgv.DefaultCellStyle.BackColor = Color.White;
dgv.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
dgv.Width = 600;
dgv.Dock = DockStyle.Left;
this.BackColor = Color.White;
dgv.Columns.Add("Col1", "Col1");
dgv.Columns.Add("Col2", "Col2");
dgv.Columns[0].Width = 110;
dgv.Columns[1].Width = 40;
dgv.DefaultCellStyle.Font = new System.Drawing.Font("Segoe UI", 10);
dgv.RowHeadersVisible = dgv.ColumnHeadersVisible = false;
dgv.AllowUserToAddRows =
dgv.AllowUserToDeleteRows =
dgv.AllowUserToOrderColumns =
dgv.AllowUserToResizeColumns =
dgv.AllowUserToResizeRows =
!(dgv.ReadOnly = true);
Controls.Add(dgv);
}
void addJobRow(string jobNum, string jobHours)
{
dgv.Rows.Add(new string[] {jobNum, jobHours });
}
void addDateRow(string date)
{
dgv.Rows.Add(new string[] { date, ""});
dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.SelectionForeColor =
dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.ForeColor = Color.Firebrick;
dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.Font = new Font("Segoe UI Light", 13.5F);
dgv.Rows[dgv.Rows.Count - 1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
dgv.Rows[dgv.Rows.Count - 1].Height = 25;
}
List<JOBS> prepareXML(string fileName)
{
string xmlContent = "";
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
using (StreamReader sr = new StreamReader(fs)) xmlContent = sr.ReadToEnd();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlContent);
List<JOBS> jobsList = new List<JOBS>();
XmlNode form1Node = doc.ChildNodes[1];
for (int i = 0; i < form1Node.ChildNodes.Count; i++)
{
XmlNode dateNode = form1Node.ChildNodes[i].ChildNodes[0].ChildNodes[0],
jobNumNode = form1Node.ChildNodes[i].ChildNodes[1].ChildNodes[0],
timeTicksNode = form1Node.ChildNodes[i].ChildNodes[6].ChildNodes[0];
bool foundDate = false;
for (int j = 0; j < jobsList.Count; j++) if (jobsList[j].compareDate(dateNode.Value))
{
jobsList[j].addJob(jobNumNode.Value, Math.Round(TimeSpan.FromTicks(
(long)Convert.ToDouble(timeTicksNode.Value)).TotalHours, 2).ToString());
foundDate = true;
break;
}
if (!foundDate)
{
JOBS job = new JOBS(dateNode.Value);
string jbnum = jobNumNode.Value;
string tbtck = timeTicksNode.Value;
long tktk = Convert.ToInt64(tbtck);
double tkdb = TimeSpan.FromTicks(tktk).TotalHours;
job.addJob(jobNumNode.Value, Math.Round(TimeSpan.FromTicks(
Convert.ToInt64(timeTicksNode.Value)).TotalHours, 2).ToString());
jobsList.Add(job);
}
}
jobsList.OrderByDescending(x => x.jobDate);
return jobsList;
}
class JOBS
{
public DateTime jobDate;
public List<JobDetails> jobDetailsList = new List<JobDetails>();
public void addJob(string jobNumber, string jobHours)
{
jobDetailsList.Add(new JobDetails() { JobHours = jobHours, JobNumber = jobNumber });
}
public JOBS(string dateString)
{
jobDate = getDateFromString(dateString);
}
public JOBS() { }
public bool compareDate(string dateString)
{
return getDateFromString(dateString) == jobDate;
}
private DateTime getDateFromString(string dateString)
{
string[] vals = dateString.Split('/');
return new DateTime(Convert.ToInt32(vals[2]), Convert.ToInt32(vals[0]), Convert.ToInt32(vals[1]));
}
}
class JobDetails
{
public string JobNumber { get; set; }
public string JobHours { get; set; }
}
}

How do I make List of Lists? And then add to each List values?

class ExtractLinks
{
WebClient contents = new WebClient();
string cont;
List<string> links = new List<string>();
List<string> FilteredLinks = new List<string>();
List<string> Respones = new List<string>();
List<List<string>> Threads = new List<List<string>>();
public void Links(string FileName)
{
HtmlDocument doc = new HtmlDocument();
doc.Load(FileName);
foreach (HtmlNode link in doc.DocumentNode.SelectNodes("//a[#href]"))
{
HtmlAttribute att = link.Attributes["href"];
if (att.Value.StartsWith("http://rotter.net/forum/scoops1"))
{
links.Add(att.Value);
}
}
for (int i = 0; i < links.Count; i++)
{
int f = links[i].IndexOf("#");
string test = links[i].Substring(0, f);
FilteredLinks.Add(test);
}
for (int i = 0; i < FilteredLinks.Count; i++)
{
contents.Encoding = System.Text.Encoding.GetEncoding(1255);
cont = contents.DownloadString(FilteredLinks[i]);
GetResponsers(cont);
}
}
private void GetResponsers(string contents)
{
int f = 0;
int startPos = 0;
while (true)
{
string firstTag = "<FONT CLASS='text16b'>";
string lastTag = "&n";
f = contents.IndexOf(firstTag, startPos);
if (f == -1)
{
break;
}
int g = contents.IndexOf(lastTag, f);
startPos = g + lastTag.Length;
string responser = contents.Substring(f + firstTag.Length, g - f - firstTag.Length);
foreach (List<string> subList in Threads)
{
}
}
}
}
I created this variable :
List<List<string>> Threads = new List<List<string>>();
The first thing I don't know yet how to do is how to create inside Threads number of Lists according to the FilteredLinks.Count inside the Links method.
Second thing is in the GetResponsers method I did:
foreach (List<string> subList in Threads)
{
}
But what I want is that first time it will add all the values from variable responser to the first List in Threads. Then when it's getting to the break; it stop then and then in the Links methods its calling GetResponsers(cont); again this time I want that all the values in responser to be added to the second List in Threads.
I know that each time it's getting to the break; it will get the next FilteredLink from FilteredLinks.
How do I create number of Lists in Threads according to the FilteredLinks.Count?
How do I make the code in GetResponsers to add the responser ?
You don't need to specify the count for the number of lists in Threads, since it is a list, you can simply keep adding lists to it. So the first part is correct where you are declaring it.
The second part --> Your calling method will change. Look below for the calling method.
The third part --> Change private void GetResponsers(string contents) to private void GetResponsers(List threadList, string contents). Look below for implementation change.
Also the loop will look like this then
//other code you have
List<List<string>> Threads = new List<List<string>>();
public void Links(string FileName)
{
// ...other code you have
for (int i = 0; i < FilteredLinks.Count; i++)
{
threads.Add(new List<string>);
contents.Encoding = System.Text.Encoding.GetEncoding(1255);
cont = contents.DownloadString(FilteredLinks[i]);
GetResponsers(threads[threads.Count - 1], cont);
}
}
private void GetResponsers(List<string> threadList, string contents)
{
int f = 0;
int startPos = 0;
while (true)
{
string firstTag = "<FONT CLASS='text16b'>";
string lastTag = "&n";
f = contents.IndexOf(firstTag, startPos);
if (f == -1)
{
break;
}
int g = contents.IndexOf(lastTag, f);
startPos = g + lastTag.Length;
string responser = contents.Substring(f + firstTag.Length, g - f - firstTag.Length);
threadList.Add(responser);
}
}
PS: Please excuse the formatting.
How do i make List of Lists ? And then add to each List values?
The following codesnippet demonstrates you, how to handle List<List<string>>.
List<List<string>> threads = new List<List<string>>();
List<string> list1 = new List<string>();
list1.Add("List1_1");
list1.Add("List1_2")
threads.Add(list1);
List<string> list2 = new List<string>();
list1.Add("List2_1");
list1.Add("List2_2")
list1.Add("List2_3")
threads.Add(list2);
How do i create number of Lists in Threads according to the
FilteredLinks.Count ?
for(int i = 0; i < FilteredLinks.Count; i++)
{
var newList = new List<string>();
newList.Add("item1"); //add whatever you wish, here.
newList.Add("item2");
Threads.Add(newList);
}
I'm afraid I can't help you with Question #2, since I don't understand what you try to achieve there exactly.

Categories