I'm working on an app that extracts content from a game page (example), displays it to the user in a textbox and if the user wishes to do so, he/she can save it as a .txt file or .xsl (excel spreadsheet format).
But the main problem I'm facing right now is that you have to manually change the code to "extract" data about another in-game unit.
If you open the link you'll see that I'm currently extracting the "Weapons", "Used", "Survived" and "Casualties" from the Defender side (as for now), but only 1 type of unit (more like only 1 row of that table) is being "extracted", I'm looking for a way to search "tr[1]/td[2]/span[1]" through "tr[45]/td[2]/span[1]" (even if the example page only goes until tr[16]), or maybe a way to automate it to search until it finds no data (nothing) then it would stop.
Sorry for any text mistakes, I'm not a native speaker
private void btnStart_Click(object sender, RoutedEventArgs e)
{
HtmlDocument brPage = new HtmlWeb().Load("http://us.desert-operations.com/world2/battleReport.php?code=f8d77b1328c8ce09ec398a78505fc465");
HtmlNodeCollection nodes = brPage.DocumentNode.SelectNodes("/html[1]/body[1]/div[1]/div[1]/div[3]/div[1]/div[1]/div[1]/div[2]/table[2]");
string result = "";
List<brContentSaver> ContentList = new List<brContentSaver>();
foreach (var item in nodes)
{
brContentSaver cL = new brContentSaver();
/* Here comes the junk handler, replaces all junk for nothing, essentially deleting it
I wish I knew a way to do this efficiently */
cL.Weapons = item.SelectSingleNode("tr[16]/td[1]").InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
cL.Used = item.SelectSingleNode("tr[16]/td[2]/span[1]").InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
cL.Survived = item.SelectSingleNode("tr[16]/td[3]").InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
if (cL.Survived == "0")
{
cL.Casualties = cL.Used;
} else
{
/* int Casualties = int.Parse(cL.Casualties);
* int Used = int.Parse(cL.Used);
* int Survived = int.Parse(cL.Survived);
* Casualties = Used - Survived; */
cL.Casualties = item.SelectSingleNode("tr[16]/td[4]").InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
}
ContentList.Add(cL);
}
foreach (var item in ContentList)
{
result += item.Weapons + " " + item.Used + " " + item.Survived + " " + item.Casualties + Environment.NewLine;
}
brContent.Text = result;
}
Sorry if this sounds silly, but I'm new to programming, especially in C#.
Edit 1: I noticed that "if (cL.Survived == "0")", I was just testing stuff some stuff way earlier and I forgot to change it, but hey, it works
Edit 2: If you are wondering I'm also using this:
public class brContentSaver
{
public string Weapons
{
get;
set;
}
public string Used
{
get;
set;
}
public string Survived
{
get;
set;
}
public string Casualties
{
get;
set;
}
}
I don't have much time to write this but hope it will help if you still need. I find Linq is more handy:
private static void Run()
{
HtmlDocument brPage = new HtmlWeb().Load("http://us.desert-operations.com/world2/battleReport.php?code=f8d77b1328c8ce09ec398a78505fc465");
var nodes = brPage.DocumentNode.Descendants("table").Where(_ => _.Attributes["class"] != null && _.Attributes["class"].Value != null && _.Attributes["class"].Value.Contains("battleReport"));
string result = "";
List<brContentSaver> ContentList = new List<brContentSaver>();
foreach (var item in nodes)
{
if (item.Descendants("th").Any(_ => _.InnerText.Equals("Weapons")))
{
//get all tr nodes except first one (header)
var trNodes = item.Descendants("tr").Skip(1);
foreach (var node in trNodes)
{
brContentSaver cL = new brContentSaver();
var tds = node.Descendants("td").ToArray();
/* Here comes the junk handler, replaces all junk for nothing, essentially deleting it
I wish I knew a way to do this efficiently */
cL.Weapons = tds[0].InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
cL.Used = tds[1].Descendants("span").FirstOrDefault()?.InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
if (string.IsNullOrEmpty(cL.Used))
{
cL.Used = tds[1].InnerText;
}
cL.Survived = tds[2].Descendants("span").FirstOrDefault()?.InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
if (string.IsNullOrEmpty(cL.Survived))
{
cL.Casualties = cL.Used;
}
else
{
/* int Casualties = int.Parse(cL.Casualties);
* int Used = int.Parse(cL.Used);
* int Survived = int.Parse(cL.Survived);
* Casualties = Used - Survived; */
cL.Casualties = tds[3].Descendants("span").FirstOrDefault()?.InnerText
.Replace(" * ", " ")
.Replace("  ; *  ;", " ");
if (string.IsNullOrEmpty(cL.Casualties))
{
cL.Casualties = tds[3].InnerText;
}
}
ContentList.Add(cL);
}
}
}
foreach (var item in ContentList)
{
result += item.Weapons + " " + item.Used + " " + item.Survived + " " + item.Casualties + Environment.NewLine;
}
var text = result;
}
Related
I'm currently working on finding a way to Log UserActions/Requests. I'm inclined towards logging the details to a text file. The LOG details are organized in a tree-like (hierarchical) structure so that it is readable and shows method names in a step-by-step manner. (if a request went through several methods)
I have a sample app which works fine but it is not the way how it should be. Consider the following classes.
Node class which is the template to make a tree-like (hierarchical) structure. It has attributes such as name (method name), Time and a List type para named Children.
public class Node
{
public string Name; // method name
public DateTime Time; // time when accessed
public List<Node> Children;
public static void PrintTree(Node tree)
{
string temp = "";
List<Node> firstStack = new List<Node>();
firstStack.Add(tree);
List<List<Node>> childListStack = new List<List<Node>>();
childListStack.Add(firstStack);
while (childListStack.Count > 0)
{
List<Node> childStack = childListStack[childListStack.Count - 1];
if (childStack.Count == 0)
{
childListStack.RemoveAt(childListStack.Count - 1);
}
else
{
tree = childStack[0];
childStack.RemoveAt(0);
string indent = "";
for (int i = 0; i < childListStack.Count - 1; i++)
{
indent += (childListStack[i].Count > 0) ? "| " : " ";
}
temp = indent + "+- " + tree.Name + " (" + tree.Time + ")";
Console.WriteLine(indent + "+- " + tree.Name + " (" + tree.Time + ")");
File.AppendAllText(#"C:\Users\aimalkhan\Desktop\Log Work\Log.txt", temp + Environment.NewLine);
if (tree.Children != null)
{
if (tree.Children.Count > 0)
{
childListStack.Add(new List<Node>(tree.Children));
}
}
}
}
File.AppendAllText(#"C:\Users\aimalkhan\Desktop\Log Work\Log.txt", Environment.NewLine + "*************************************************************" + Environment.NewLine);
}
}
My sample Employee class with a sample method SetEmployeeName() having AN EXTRA parameter of NODE type for Logging purposes.
public class Employee
{
private string FirstName { get; set; }
private string LastName { get; set; }
public string SetEmployeeName(string firstName, string lastName, Node node)
{
node.Name = "Class Name: " +this.GetType().Name + ", Calling method Name: setEmployeeName()";
node.Time = DateTime.Now;
this.FirstName = firstName;
this.LastName = lastName;
return this.FirstName + " " + this.LastName;
}
public void CompleteTask(string empName, string taskName)
{
Console.WriteLine("Employee: " + empName + " is completing the task: " + taskName);
}
}
and finally this is how i'm using the aforementioned sample of Codes.
Node root = new Node();
root.Name = "ClassName: Main";
root.Time = DateTime.Now;
root.Children = new List<Node>();
Node child = new Node();
Employee emp = new Employee();
emp.SetEmployeeName("John", "D", child);
root.Children.Add(child);
Node.PrintTree(root);
This is how the output looks
Now my question is that it would really be a headache for me to pass a NODE type para every time i need a child info log. Could this be some how made centralized in any possible way? Is there a better way than this one? A little guidance would really be appreciated.
I'm doing a WCF service with GUI as client, however I have a problem with printing list of current items added. I have a code to add new entries to the list:
public bool Add_Data(Data sample)
{
container.Add(sample);
Console.WriteLine("New record added!");
return true;
}
And it's working, however when I'm trying to view added records with first try it works, however if I want to view it again list is adding same element. To show you how it works:
I'm adding new entry and I "print" list:
IMAGE CLICK [works how it should]
However I want to see it again, so I'm pressing same button in my form, and here is what happens:IMAGE CLICK as you can see, we have our list + additional same record, if I will press button again, I will have 3 same records.
Here is my "show records" code:
public string Show_Data()
{
Console.WriteLine("Printing records");
foreach (Data record in container)
{
string final_result = ("\nID: "+ + record.ID + " " + "product: " + record.product + " " + "category: " + record.category + " " + "price: " + record.price + " " + "quantity: " + record.quantity + " " + "\n ");
result += final_result;
}
return result;
}
Let me know if you know how to solve it.
You need to look into variable scope. You have result declared outside of the Show_Data() method. Each time the method is called you are doing result += final_result; which is adding to result. Try the code below and you will get different results.
public string Show_Data()
{
Console.WriteLine("Printing records");
var output = string.Empty;
foreach (Data record in container)
{
string final_result = ("\nID: "+ + record.ID + " " + "product: " + record.product + " " + "category: " + record.category + " " + "price: " + record.price + " " + "quantity: " + record.quantity + " " + "\n ");
output += final_result;
}
return output;
}
Also, I would consider using a string builder and string format as well.
public string Show_Data()
{
Console.WriteLine("Printing records");
var output = new StringBuilder();
foreach (Data record in container)
{
string final_result = string.Format("ID: {0} product: {1} category: {2} price: {3} quantity: {4}", record.ID, record.product, record.category, record.price, record.quantity);
// if using C# 6
// string final_result = string.Format($"ID: {record.ID} product: {record.product} category: {record.category} price: {record.price} quantity: {record.quantity)}";
output.AppendLine(final_result);
}
return output.ToString();
}
I'm trying to search for a certain number(object) in a listbox which comes together with a string in order to highlight it. In the following bit of code i override a ToString() method to contain all my objects.
public override string ToString()
{
string reservatiestring;
reservatiestring = "Kamer: " + roomNumber + "" + " Op datum: " + datum + " Aantal personen: " + personen.Count + " Naam: " + reservatienaam;
return reservatiestring;
}
Following this I add it to my listbox in the following bit of code:
listBox1.Items.Add(reservatie.ToString());
I now want to search for all the items in my listbox containing the same roomNumber object. To do this i tried the Contains() method with the text before it: "Kamer: " and the object which I'm looking for +comboBox1.SelectedItem. This however always fails and my code goes to the else option giving me the error message.
private void buttonSearch_Click(object sender, EventArgs e)
{
listBox1.SelectionMode = SelectionMode.MultiExtended;
Reservations reservaties = new Reservations();
reservaties.roomnumberstring = "Kamer: " + comboBox1.SelectedValue;
for (int i = listBox1.Items.Count - 1; i >= 0; i--)
{
if (listBox1.Items[i].ToString().ToLower().Contains(("Kamer: " + comboBox1.SelectedValue)))
{
listBox1.SetSelected(i, true);
}
else
{
MessageBox.Show("error");
}
Please note: All my roomNumber objects are stored in the combobox, so whenever i select for example roomNumber 3 in my combobox and hit search all the items in the listbox containing "Kamer: 3" should be selected.
The roomnumberstring is a option I tried which did not work unfortunately.
reservaties.roomnumberstring = "Kamer: " + comboBox1.SelectedValue;
Your override of the ToString method is wrong and won't modify anything. Try this :
public override string ToString(this string reservatiestring)
{
reservatiestring = "Kamer: " + roomNumber + "" + " Op datum: " + datum + " Aantal personen: " + personen.Count + " Naam: " + reservatienaam;
return reservatiestring;
}
I can see one thing that might make your code fail. you are comparing
.ToLower()
with "Kamer", where the "K" isnĀ“t in lowercase
I have a function that retrieves multiple lines of data and I want to display them in a label. My function is as shown below.
public static string GetItemByQuery(IAmazonSimpleDB simpleDBClient, string domainName)
{
SelectResponse response = simpleDBClient.Select(new SelectRequest()
{
SelectExpression = "Select * from " + domainName
});
String res = domainName + " has: ";
foreach (Item item in response.Items)
{
res = item.Name + ": ";
foreach (Amazon.SimpleDB.Model.Attribute attribute in item.Attributes)
{
res += "{" + attribute.Name + ", " + attribute.Value + "}, ";
}
res = res.Remove(res.Length - 2);
}
return res;
}
So far I can only return a string which is the last line of the retrieved data. How can I retrieve all the records? I tries arraylist, but it seems that the AWS web application doesn't allow me to use arraylist. Can anyone please help me to solve this??
Return it as as a Enumberable,
List<String> Results ;
Your method would be
public static List<String> GetItemByQuery(IAmazonSimpleDB simpleDBClient, string domainName)
{
List<String> Results = null;
SelectResponse response = simpleDBClient.Select(new SelectRequest()
{
SelectExpression = "Select * from " + domainName
});
String res = domainName + " has: ";
foreach (Item item in response.Items)
{
Results = new List<String>();
res = item.Name + ": ";
foreach (Amazon.SimpleDB.Model.Attribute attribute in item.Attributes)
{
res += "{" + attribute.Name + ", " + attribute.Value + "}, ";
}
res = res.Remove(res.Length - 2);
Results.Add(res);
}
return Results;
}
Sometime it has been seen that the HTML source that we receive from some website are not having proper tag ending, and that affect our UI.
So, like
<br /><p>hello the para start here </p> <p>some text and no ending tag
And there is no ending tag .
I want to retain the HTML format and want this like
<br /><p>hello the para start here </p> some text and no ending tag
One more thing is that sometimes we get the end tag at the start that should also be resolved by the algorithm.
Hey guys I thought for a long time and finally I have code for my problem, i am posting it here so that other can get benefit from this ....
public static string RemoveIncompleteTags(string source, string tag)
{
source = source.Replace(" ", " ");
source = source.Replace("/n", string.Empty).Replace("/r", string.Empty).Replace("/t", string.Empty);
source = source.Replace("<" + tag + "></" + tag + ">", string.Empty);
source = source.Replace("<" + tag + "> </" + tag + ">", string.Empty);
source = source.Replace("<" + tag + "> </" + tag + ">", string.Empty);
Dictionary<int, string> oDict = new Dictionary<int, string>();
string[] souceList;
Dictionary<int, string> final = new Dictionary<int, string>();
bool opening = false;
bool operate = false;
source = source.Replace(" ", " ");
source = source.Replace(">", "> ").Replace("<", " <");
source = source.Replace(" >", ">").Replace("< ", "<");
source = source.Replace(" ", " ").Replace(" ", " ");
souceList = source.Split(' ');
for (int i = 0; i < souceList.Length; i++)
{
string word = souceList[i];
if (word.ToLower() == "<" + tag.ToLower() + ">")
{
opening = true;
operate = true;
}
else if (word.ToLower() == "</" + tag.ToLower() + ">")
{
opening = false;
operate = true;
}
if (operate)
{
if (opening)
{
oDict.Add(i, word);
final.Add(i, word);
}
else
{
if (oDict.Count != 0)
{
oDict.Remove(oDict.Last().Key);//.ToList().RemoveAt(oDict.Count - 1);
final.Add(i, word);
}
else
{
// need not to add to the output string
// code if you want to log
}
}
operate = false;
opening = false;
}
else
{
final.Add(i, word);
}
}
if (final.Count > 0)
{
if (oDict.Count > 0)
{
foreach (var key in oDict.Keys)
{
final.Remove(key);
}
}
StringBuilder fText = new StringBuilder();
final.ToList().ForEach(wd =>
{
if (wd.Value.Trim().Length > 0)
fText.Append(wd.Value.Trim() + " ");
});
return fText.ToString().Trim();
}
else
{
return string.Empty;
}
}
thanks...