Nested list of SQL query result - c#

After I run my query I have got the result into a dataTable as the following (this is only a simplified resultset):
food_cat food
-----------------------
vegit carrot
vegit onion
vegit tomato
fruit cherry
fruit banana
fruit orange
I want to list that result grouped by food_cat in an unordered list.
<h3> Vegit </h3>
<ul>
<li>carrot</li>
<li>onion</li>
<li>tomato</ti>
</ul>
<h3>fruit</h3>
<ul>
<li>cherry</li>
<li>banana</li>
<li>orange</li>
</ul>
I have tried some for, if, while controls but could not find a good solution.

since you don't provide table names etc. i will try to give the answer in general way.
string previous_food_cat = '';
bool firstEntrance = true
while(trace resultSet until no elements left)
{
if resultSet.food_cat != previous_food_cat //check if food_cat value changed
{
if (!firstEntrance) //if not first entrance close the <ul> tag before opening new one
{
print </ul>
}
print <h3> resultSet.food_cat </h3> //open new <h3> tag
print <ul> //open new <ul> tag
previous_food_cat = resultSet.food_cat //update previous_food_cat for new food_cat value
firstEntrance = false //set firstEntrance false so that ul tqags should be closed
}
print <li> resultSet.food </li>
}

Thank you #zibidyum, your technic obtained me to reach a solution. But final solution is here:
public bool firstcat; // defined at before Page_Load method
public int temp_cat; // defined at before Page_Load method
for (int i = 0; i < dt.Rows.Count; i++)
{
if (temp_cat != Convert.ToInt32(dt.Rows[i]["food_cat"]))
{
if (i > 0 && !firstcat)
content.InnerHtml += "</ul>"; //solution's most critic point is here
content.InnerHtml += "<ul>"
}
content.InnerHtml += String.Format("<li>{0}</li>", dt.Rows[i]["food"].ToString());
temp_cat = Convert.ToInt32(dt.Rows[i]["food_cat"]);
}
Any better solutions, suggestions and/or ideas are welcome.

Related

Assert all the li in the div in coded UI test

<div class="validation-summary-errors">
<span>Please check the following entries:</span>
<ul>
<li>Please select a client account</li>
<li>Please select a beneficiary account</li>
</ul>
</div>
public virtual T VerifyAmountValidationMessages()
{
HtmlDiv error = new HtmlDiv(_browserWindow);
error.SearchProperties[HtmlDiv.PropertyNames.Class] = "validation-summary-errors";
var errors = error.FindMatchingControls();
var errorLi = error.GetChildren()[0];
foreach (var item in errors)
{
Assert.IsTrue(item.GetProperty("InnerText").ToString().Contains("Please check the following entries:\r\nPlease select a client account\r\nPlease select a beneficiary account"));
}
return (T)this;
}
How can I iterate all the lis and assert the inner text of each Li, with the getChildren I can access the span element individually but I want to access the Li individually? Right Now I am asserting the whole text which is not the correct approach at all.
The ul element would be errors.GetChildren()[0]; you would them loop over its children.
<div class="validation-summary-errors">
<span>Please check the following entries:</span>
<ul>
<li>Please select a client account</li>
<li>Please select a beneficiary account</li>
</ul>
</div>
public virtual T VerifyAmountValidationMessages()
{
HtmlDiv error = new HtmlDiv(_browserWindow);
error.SearchProperties[HtmlDiv.PropertyNames.Class] = "validation-summary-errors";
var errors = error.FindMatchingControls();
var errorul = error.GetChildren()[1];
foreach (var item in errors
{
// check individual li items
}
return (T)this;
}
This would seem to be a brittle test though, consider if any changes are made to how errors are displayed, you'll have to rewrite the test.

Can't solve this html generating puzzle

I have a Tree on which I perform a depth-first algorithm. It creates a list of the Tree in the order of which the elements should come in the HTML.
I use this to generate the HTML to be displayed on the view. (each element that is a question has 2 elements, an answer has none; answer is the leaf; question the branch)
var html = "<ul>";
foreach (var c in listWithElements)
{
html += "<li>";
if (c is Question)
{
var v = (Question)c;
html += v.Content + "<ul>";
}
else
{
var t = (Answer)c;
html += t.Content + "</li>";
}
}
return html + "</ul>";
This generates a perfect structure:
<ul>
<li>QUESTION
<ul>
<li>QUESTION
<ul>
<li>ANSWER</li>
<li>ANSWER</li>
**</ul>**
<li>QUESTION
<ul>
<li>ANSWER</li>
<li>QUESTION
<ul>
<li>QUESTION
<ul>
<li>ANSWER</li>
<li>ANSWER</li>
**</ul>**
<li>ANSWER</li>
**</ul>**
</li>
**</ul>**
</li>
**</ul>**
</li>
<li>ANSWER</li>
</ul>
Except the HTML generation part does not create the ul closing tags. It's not that I haven't tried, it's just I can't seem to find a pattern to determine when/where to insert them. I've temporarily added the closing tags to make it more clear where they should be put.
The only pattern I could find was: the tag should be put after the second DIRECT li child's closing tag of an ul.
Any help?
You can't. You need more information about each node. For example, if you look at this bit:
> <ul>
> <li>ANSWER</li>
> <li>ANSWER</li>
> **</ul>**
> <li>ANSWER</li>
There is no way for your code to "know" there should be a "/ul" there. It simply isn't given enough information by looping through. You would need to have some kind of marker on the Answer object that says "this is the last answer in the current group" or something.
You can do something like this: (I've tested it in fiddle sample and it seems to be working great)
var html = "<ul>";
var stack = [];
var pointer = 0;
stack.push(0);
foreach (var c in listWithElements)
{
while (stack[pointer]==2&& pointer>0){
html += "</ul>";
stack.pop();
pointer--;
}
stack[pointer]++;
html += "<li>";
if (c is Question)
{
stack.push(0);
pointer++;
var v = (Question)c;
html += v.Content + "<ul>";
}
else
{
var t = (Answer)c;
html += t.Content + "</li>";
}
}
return html + "</ul>";
working fiddle example - fiddle
edit: This solution is for JS, but it is same in C# with lists:
static void Main(string[] args)
{
Console.WriteLine("<ul>");
string[] listWithElements = { "q", "a", "a", "q", "a", "q", "a", "a", "q" };
List<int> stack = new List<int>();
stack.Add(0);
foreach (var c in listWithElements)
{
while (stack[stack.Count() - 1] == 2 && stack.Count() > 1)
{
Console.WriteLine("</ul>");
stack.RemoveAt(stack.Count() - 1);
}
stack[stack.Count() - 1]++;
Console.WriteLine("<li>");
if (listWithElements[stack.Count() - 1] == "q")
{
stack.Add(0);
Console.WriteLine("qqq");
Console.WriteLine("<ul>");
}
else
{
Console.WriteLine("aaa");
Console.WriteLine("</li>");
}
}
Console.WriteLine("</ul>");
}
It would be pretty simple with depthfirst search. If you step one step deeper (away from the root) print the opening tag and the content of the node you are now at. If you go one step out (to the root) print the closing tag for the node before doing the step. Just leave out the step with converting the tree into a list and things get pretty simple.
define node: {string content}
define question: node AND {node right , node left}
define answer: node
define toHTML:
input: node root
output: string html
list visited
stack stack
push(stack , root)
add(visited , root)
while ! isEmpty(stack)
node n = first(stack)
add(visited , n)
append(getContent(n))
if isAnswer(n)
remove(stack , n)
else
question q = (question) n
if contains(visited , q.left)
if contains(visited , q.right)
pop(stack)
append(html , closingTag(q))//append the closingtag of the question
else
push(stack , q.right)
else
push(stack , q.left)

Checking Umbraco node length

I have a panel that is created and filled via a vacancy page I have created. Im doing it as follows:
#{
var root = CurrentPage.AncestorOrSelf(1);
var newsNode = root.Descendants("News").First();
var vacanciesNode = root.Descendants("Vacancies").First();
string shortenedSummary = string.Empty;
}
<ul>
#foreach (var vacancyItem in vacanciesNode.Descendants("Vacancy").Take(3).OrderBy("postDate desc"))
{
<p>here we are 2</p>
#vacanciesNode.Count().ToString()
<li>
<h4>#vacancyItem.jobTitle</h4> <span>Posted on #vacancyItem.postDate.ToString("dd/MM/yyyy")</span>
<p>
#if (vacancyItem.jobSummary.Length <= 182)
{
#vacancyItem.jobSummary
}
else
{
shortenedSummary = vacancyItem.jobSummary.Substring(0, 182) + "...";
#shortenedSummary
}
</p>
Read More..
</li>
}
</ul>
However, when there are no vacancy items, my list is empty. Should this be the case, I'm wanting it to read "sorry no vacancies just now" but I don't know how to check if my vacanciesNode has any items in it.
Could someone show me how I could achieve this?
Since the .Descendants() method returns a DynamicContentList (a collection) you can simply do a .Count() on the collection and check whether it's more than or equal to 1.
If there's more than 0 items in the collection, it's not empty.
So, what you need to do is surround your #foreach with an #if statement which checks on this, and an else statement after that prints whatever html you want to show if there's no vacancies
#if( vacanciesNode.Descendants("Vacancy").Take(3).OrderBy("postDate desc").Count() > 0) {
//Do foreach
}
else
{
//Write message about missing vacancies
}

C#;WebDriver: String array is coming up null when attempting to click using linktext

I am trying to read the following list:
<ol class="sublist">
<li>
Sort Out Your Values
</li>
<li>
Establish Realistic Goals
</li>
<li>
Determine Your Monthly Net Income
This is the code i wrote for it; but currently, everytime it runs; my string is coming up empty. I want to get the inner text so that in my loop i grab it and click it and return back to previous screen.
IWebElement container = driver.FindElement(By.ClassName("sublist"));
IList<IWebElement> elements = driver.FindElements(By.TagName("a"));
string [] newlink = new string[elements.Count()];
for (int i = 0; i < newlink.Count(); i++)
{
if (newlink[i] != null)
{
driver.FindElement(By.LinkText(newlink[i])).Click();
driver.WaitForElement(By.CssSelector("[id$='hlnkPrint']"));
driver.Navigate().Back();
}
}
The script is able to run but was getting that the links were null, so i added a check to see if any of them were null and it turns out all of them are.
Im sure it has something to do with with the '.text' or 'ToString', but Im not sure where to implement that.
Thanks
There's a few issues with your code.
- You haven't set the value of newlink, just created it.
- Count is a property, but you're using it as a method.
- Link text is the .Text property of an IWebElement, and you would need to access that.
- Your current code will likely click one link, and after going back will throw a StaleElementException.
In the following
- I set newlink to the Text values of the links found for elements
- I then iterate through the array of link text
IWebElement container = driver.FindElement(By.ClassName("sublist"));
IList<IWebElement> elements = container.FindElements(By.TagName("a"));
string[] newlink = new string[elements.Count];
for (int i = 0; i < newlink.Count; i++)
{
newlink[i] = elements[i].Text;
}
for (int i = 0; i < newlink.Count; i++)
{
if (newlink[i] != null)
{
driver.FindElement(By.LinkText(newlink[i])).Click();
driver.WaitForElement(By.CssSelector("[id$='hlnkPrint']"));
driver.Navigate().Back();
}
}
You can use FindElement() on an IWebElement. so in this case, if you want to find elements that are children of container, you would use container.FindElements().

hide multiple <li> list items in code-behind

I have a very huge unordered list items in my masterpage. say it contains 60+ list items. depending on some condition i want hide that list items (hidden items could be 1 to 59 )
My Master File Code Snippet :
<li>Authorization
<ul>
<li><span>Card Request</span></li>
<li><span>Card Issue</span></li>
<li><span>Card Reload</span></li>
<li><span>Close Card</span></li>
<li><span>Card Replacement</span></li>
<li><span>Card Status Change</span></li>
<li><span>Upgrade/DownGrade</span></li>
</ul>
</li>
Condition : -
My DataTable returns values like
cardIssueAuth.aspx
Distributor.aspx
CardStatuschangeAuth.aspx
UpgradeDowngradeAuth.aspx
So i want to hide only those page which came in DataTable
I am aware of ID & runat attribute of <li> & then make it visible : false
But how can i use it efficiently/dynamically ? by using some for loop ...!!
I personally donot like the 'visibility' hack. You could selectively render the 'li' elements on the server-side itself (via code-behind or scriptlets) based on the entries on DataTable.
On the code-behind, you could have a static dictionary that contains all the link details, grouped by sections. Plus the filtering logic:
var sections = new List<Section>()
{
new Section()
{
Header = "Authorization",
SubLinkDetails = new Dictionary<string, string>()
{
{"NewCardGeneration.aspx", "Card Request"},
{"cardIssueAuth.aspx", "Card Issue"},
//.. and so on
}
}
//.. other sections follow
};
//filter subLinkDetails depending on the DataTable entries
sections.ForEach(s => s.SubLinkDetails.RemoveWhere(k => DataTable.Contains(k)));
Here, the Section is a convenience class and RemoveWhere is an extension method on IDictionary:
class Section
{
public string Header { get; set; }
public IDictionary<string,string> SubLinkDetails { get; set; }
}
public static class IDictionaryX
{
public static void RemoveWhere<K,V>(this IDictionary<K,V> dictionary, Predicate<K> condition)
{
IEnumerable<K> keysToRemove = dictionary.Keys.Where(k => condition(k));
foreach (var k in keysToRemove)
{
dictionary.Remove(k);
}
}
}
In your aspx, access the sections and render the ul/li elements:
<%foreach (var section in sections)
{%>
<li><%=section.Header %>
<%foreach (var filteredLink in section.SubLinkDetails)
{%>
<li><span>"<%= filteredLink.Value>"</span></li>
<%}%>
</li>
<%}%>
Provide id to your <li> according to page names.
And then,
You can do this by
if (listItem.selectedItem == 'pagename.aspx')
this.hide.style.Add("display", "none");

Categories