selecting divs fails - asp.net-mvc-4

I am trying to parse the information inside the div class="base shortstory:
<div id="dle-content">
<div class="base shortstory">
<h3 class="btl">HTC Jetstream</h3>
</div>
<div class="base shortstory">
<h3 class="btl">Samsung S4</h3>
</div>
<div class="base shortstory">
<h3 class="btl">Dell Streak</h3>
</div>
</div>
Here is the code
const string url = "http://someurl.com/catalogue";
const string rootUrl = "http://someurl.com";
HtmlWeb hw = new HtmlWeb();
HtmlDocument doc = hw.Load(url);
int dealsCount = 0;
HtmlNode root = doc.DocumentNode.SelectSingleNode("//div[#id='dle-content']");
int i = 1;
//this is for the default page
while (i<=10)
{
try
{
string node= String.Format("//div[{0}]", i);
var link =
doc.DocumentNode.SelectSingleNode(node);
var href = link.SelectSingleNode("//div[#class='mlink']//span[#class='argmore']//a[#href]").Attributes["href"].Value;
string title = link.SelectSingleNode("//h3[#class='btl']//a[#href]").InnerText.Trim();
string description = link.SelectSingleNode("//div[#class='maincont']//div[1]").InnerText.Replace("\n", " ").Replace("\r", "").Replace("\t", "").Trim();
description = RemoveHTMLComments(description);
var imageURL = link.SelectSingleNode("//div[#class='maincont']//div[1]//a//img").Attributes["src"].Value;
var price = link.SelectSingleNode("//div[#class='mlink']//span[3]//font").InnerText.Trim();
price = Regex.Match(price, #"\d+").Value;
var partnerdealID = href;
//no information
var isActivesStr = link.SelectSingleNode("//div[#class='mlink']//span[2]/font").InnerText.Trim();
bool isActive;
if (isActivesStr.Contains("Нет в наличии"))
{
isActive = false;
}
else
{
isActive = true;
}
var dealUrl = href; //requires login - show the page itself
}
catch (Exception)
{
}
i += 1;
}
But after looping still the selected node is first one. What am I doing wrong?

All your XPATH expressions start with '//' which means "start from root of the document and search recursively". So when you do this:
link.SelectSingleNode("//div[#class='mlink']//span[#class='argmore']//a[#href]")
You will start not from link, but from the document's root. You probably want to do this instead:
link.SelectSingleNode("div[#class='mlink']...etc...")
which is equivalent to
link.SelectSingleNode("./div[#class='mlink']...etc...")
'.' means the current node. '/' means search only the direct children, not recursively.

Related

How to make asp-route-{value} tag helper take value from variable?

I would like to achieve the thing below:
#{
var myParam = "foo";
var myValue = 1;
}
<a asp-controller = "mycontroller" asp-action = "myaction" asp-route-#(myParam) = "#myValue">doit</a>
And it should generate this (according to a default route template):
doit
But this part does not work:
asp-route-#(myParam)
It is possible to do this?
Oh, asp-all-route-data does it.
#{
var myParam = "foo";
var myValue = 1;
var parms = new Dictionary<string, string>
{
{ myParam, myValue.ToString() }
};
}
<a asp-controller="mycontroller" asp-action="myaction" asp-all-route-data="parms">doit</a>

How to access child element in parent element

I am creating a element in which parent element is having a button. On tap of this button the properties of child element are changing. Following is the code snippet-
<parent-element>
<template is="dom-repeat" items="{{aa}}">
<child-element id="aa{{index}}">
<button on-tap="_clickFunction">
</template>
_ClickFunction(){
for(var i = 0; i < items.length; i++){
this.shadowRoot.querySelector("aa" + i).prop1 = true;
this.shadowRoot.querySelector("aa" + i).prop2 = true;
}
}
</parent-element>
<child-element>
properties:{
prop1: Boolean,
prop2: Boolean,
}
</child-element>
How does it possible without using id or any dom-manipulation.
if there is dom-repeat, how to access properties of particular child element.
Try this:
_ClickFunction(e){
let childItemIndex = e.model.index;
var childItem = this.shadowRoot.getElementById(`aa${childItemIndex}`);
item.prop1 = !!1;
item.prop2 = !!1;
}

Retrieve selected checkboxes in an array into the controller

How can i retrieve the selected checkbox in the controller.
This is the main view where the user can choose a request access.
#using (Html.BeginForm("addBatch_CARF", "CARF", FormMethod.Post, new { #name = "register" }))
{
#Html.ValidationSummary(true)
<div id="formAlert" class="alert alert-danger">
<a class="close">×</a>
<strong>Warning!</strong> Make sure all fields are filled and try again.
</div>
var catName = "";
var displayCan = "";
var candidates = "";
for (int i = 0; i < Model.Count; i++)
{
if (catName != Model[i].request_category)
{
<li class="list-group-item list-group-item-success">
#Html.DisplayFor(modelItem => Model[i].request_category)
<span class="pull-right" style="margin-right:60px;">Special Instructions</span>
</li>
catName = Model[i].request_category;
displayCan = catName;
}
if (displayCan == Model[i].request_category)
{
candidates = Model[i].request_name;
<div class="checkbox_request">
#Html.CheckBoxFor(model => model[i].isSelected, new { #class = "is_selected" })
#Html.DisplayFor(model => model[i].request_name)
#if(Model[i].request_name == "Folder Access")
{
<span class="label label-danger">Pls specify all the drive path. Note: For accessing of drives outside PETC please proceed to Online CARF</span>
}
<span class="pull-right">
#Html.EditorFor(model => model[i].special_instruction)
</span>
#Html.HiddenFor(model => model[i].request_type_id)
#Html.HiddenFor(model => model[i].system_roles_id)
</div>
}
}
<li class="list-group-item list-group-item-success">
Access to:
</li>
<div id="employeeAdd">
#{Html.RenderAction("AddRequestor"); }
</div>
<p class="request_btn">
<button type="submit" class="btn btn-primary" id="addbtn">Save</button>
</p>
}
I have only rendered this view AddRequestor in selecting or adding an employee.
<table class="table table-hover">
#for (int i = 0; i < Model.Count; i++){
<tr>
<th>
#Html.CheckBox("checkbox", new { #class = "is_selected" })
#Html.DisplayFor(model => model[i].FullName)
#Html.HiddenFor(model => model[i].Emp_Badge_No)
</th>
</tr>
}
</table>
The main goal of this is all the chosen employees must have also all the chosen request access.
[HttpPost]
public ActionResult addBatch_CARF(List<Request_Type> list, List<Employees_All_vw> emp, string[] checkboxes)
{
foreach (var x in emp)
{
int num = 1;
bool z = Convert.ToBoolean(num);
if (x.checkbox == z)
{
//add data into CARF table
CARF carf = new CARF();
carf.requestor = x.Emp_Badge_No;
carf.carf_type = "BATCH CARF";
carf.created_by = #User.Identity.Name.Remove(0, 9).ToLower();
carf.created_date = System.DateTime.Now;
carf.active_flag = true;
db.CARves.Add(carf);
db.SaveChanges();
int id = carf.carf_id;
//add data into Request Access Table
foreach (var i in list)
{
int val = 1;
bool y = Convert.ToBoolean(val);
if (i.isSelected == y)
{
Request_Access ra = new Request_Access();
ra.request_access_id = 1;
ra.carf_id = id;
ra.request_type_id = i.request_type_id;
ra.special_instruction = i.special_instruction;
ra.ra_assignee = i.system_roles_id;
ra.dept_approval = null;
ra.dept_approval_date = null;
ra.dept_remarks = null;
ra.final_approval = null;
ra.final_approval_date = null;
ra.final_remarks = null;
ra.acknowledge_by = null;
ra.acknowledge_date = null;
ra.journal = null;
ra.closed_by = null;
ra.closed_date = null;
ra.verified_by = null;
ra.verified_date = null;
db.Request_Access.Add(ra);
}
}
db.SaveChanges();
}
TempData["MessageAlert"] = "Successfully created!";
return RedirectToAction("Batch_CARF");
}
}
I've got an error on this line if (x.checkbox == z)
Operator '==' cannot be applied to operands of type 'string[]' and 'bool'
Your parameter string[] checkboxes contains values that are typeof string (either "True" or "False") so you would need to use the Convert.ToBoolean() method before comparing if (x.checkbox == z). However this will not work since #Html.CheckBox("checkbox", ..) generates 2 inputs type="checkbox" with value="True" and a type="hidden" with value="False" so if its checked, both true and false post back and if its unchecked, then only false is posted. There is no way you can possibly match up which values belong to which employee.
Instead create a view model to represent the selection of employees
public class EmployeeVM
{
public string BadgeNumber { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
And then in your AddRequestor() method (assumes you have an Employees table)
public ActionResult AddRequestor()
{
List<EmployeeVM> model = db.Employees.Where(e => e.active_flag).Select(e => new EmployeeVM
{
BadgeNumber = e.Emp_Badge_No,
Name = e.FullName
}.ToList();
return PartialView(model);
}
and in the view
#model List<EmployeeVM>
#for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => m[i].BadgeNumber)
<label>
#Html.CheckboxFor(m => m[i].IsSelected)
<span>#Html.DisplayFor(m => m[i].Name)</span>
</label>
}
And finally, in the POST method
[HttpPost]
public ActionResult addBatch_CARF(List<Request_Type> list, List<EmployeesVM> employees)
{
// To get the selected employees
IEnumerable<string> selectedEmployees = employees.Where(e => e.IsSelected);
foreach(EmployeesVM employee in selectedEmployees)
{
....
carf.requestor = employee.BadgeNumber;
....

How can I convert XHTML nested list to pdf with iText?

I have XHTML content, and I have to create from this content a PDF file on the fly. I use iText pdf converter.
I tried the simple way, but I always get bad result after calling the XMLWorkerHelper parser.
XHTML:
<ul>
<li>First
<ol>
<li>Second</li>
<li>Second</li>
</ol>
</li>
<li>First</li>
</ul>
The expected value:
First
Second
Second
First
PDF result:
First Second Second
First
In the result there is no nested list. I need a solution for calling the parser, and not creating an iText Document instance.
Please take a look at the example NestedListHtml
In this example, I take your code snippet list.html:
<ul>
<li>First
<ol>
<li>Second</li>
<li>Second</li>
</ol>
</li>
<li>First</li>
</ul>
And I parse it into an ElementList:
// CSS
CSSResolver cssResolver =
XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
// HTML
HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.autoBookmark(false);
// Pipelines
ElementList elements = new ElementList();
ElementHandlerPipeline end = new ElementHandlerPipeline(elements, null);
HtmlPipeline html = new HtmlPipeline(htmlContext, end);
CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);
// XML Worker
XMLWorker worker = new XMLWorker(css, true);
XMLParser p = new XMLParser(worker);
p.parse(new FileInputStream(HTML));
Now I can add this list to the Document:
for (Element e : elements) {
document.add(e);
}
Or I can list this list to a Paragraph:
Paragraph para = new Paragraph();
for (Element e : elements) {
para.add(e);
}
document.add(para);
You will get the desired result as shown in nested_list.pdf
You can not add nested lists to a PdfPCell or to a ColumnText. For instance: this will not work:
PdfPTable table = new PdfPTable(2);
table.addCell("Nested lists don't work in a cell");
PdfPCell cell = new PdfPCell();
for (Element e : elements) {
cell.addElement(e);
}
table.addCell(cell);
document.add(table);
This is due to a limitation in the ColumnText class that has been there for many years. We have evaluated the problem and the only way to fix this, would be to rewrite ColumnText entirely. This is not an item on our current technical road map.
Here's a workaround for nested ordered and un-ordered lists.
The rich Text editor I am using giving the class attribute "ql-indent-1/2/2/" for li tags, based on the attribute adding ul/ol starting and ending tags.
public String replaceIndentSubList(String htmlContent) {
org.jsoup.nodes.Document document = Jsoup.parseBodyFragment(htmlContent);
Elements element_UL = document.select("ul");
Elements element_OL = document.select("ol");
if (!element_UL.isEmpty()) {
htmlContent = replaceIndents(htmlContent, element_UL, "ul");
}
if (!element_OL.isEmpty()) {
htmlContent = replaceIndents(htmlContent, element_OL, "ol");
}
return htmlContent;
}
public String replaceIndents(String htmlContent, Elements element, String tagType) {
String attributeKey = "class";
String startingULTgas = "<" + tagType + ">";
String endingULTags = "</" + tagType + ">";
int lengthOfQLIndenet = new String("ql-indent-").length();
HashMap<String, String> startingLiTagMap = new HashMap<String, String>();
HashMap<String, String> lastLiTagMap = new HashMap<String, String>();
Pattern regex = Pattern.compile("ql-indent-\\d");
HashSet<String> hash_Set = new HashSet<String>();
Elements element_Tag = element.select("li");
for (org.jsoup.nodes.Element element2 : element_Tag) {
org.jsoup.nodes.Attributes att = element2.attributes();
if (att.hasKey(attributeKey)) {
String attributeValue = att.get(attributeKey);
Matcher matcher = regex.matcher(attributeValue);
if (matcher.find()) {
if (!startingLiTagMap.containsKey(attributeValue)) {
startingLiTagMap.put(attributeValue, element2.toString());
}
hash_Set.add(matcher.group(0));
if (!startingLiTagMap.get(attributeValue)
.equalsIgnoreCase(element2.toString())) {
lastLiTagMap.put(attributeValue, element2.toString());
}
}
}
}
System.out.println(htmlContent);
Iterator value = hash_Set.iterator();
while (value.hasNext()) {
String liAttributeKey = (String) value.next();
int noOfIndentes = Integer
.parseInt(liAttributeKey.substring(lengthOfQLIndenet));
if (noOfIndentes > 1)
for (int i = 1; i < noOfIndentes; i++) {
startingULTgas = startingULTgas + "<" + tagType + ">";
endingULTags = endingULTags + "</" + tagType + ">";
}
htmlContent = htmlContent.replace(startingLiTagMap.get(liAttributeKey),
startingULTgas + startingLiTagMap.get(liAttributeKey));
if (lastLiTagMap.get(liAttributeKey) != null) {
System.out.println("Inside last Li Map");
htmlContent = htmlContent.replace(lastLiTagMap.get(liAttributeKey),
lastLiTagMap.get(liAttributeKey) + endingULTags);
}
else {
htmlContent = htmlContent.replace(startingLiTagMap.get(liAttributeKey),
startingLiTagMap.get(liAttributeKey) + endingULTags);
}
startingULTgas = "<" + tagType + ">";
endingULTags = "</" + tagType + ">";
}
System.out.println(htmlContent);[enter image description here][1]
return htmlContent;
}

Index was out of range. Must be non-negative and less than the size of the collection

While trying to validate form data on my page i get the following error:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index.
my code for this page is:
#{
var db= Database.Open("Games");
var sqlQ = "SELECT * FROM Games";
var data = db.Query(sqlQ);
Page.Title = "Add Game";
}
#{
var fileerrorMessage = "";
var NameerrorMessage = "";
var Gamefile = "";
var GameName = "";
var fileData = Request.Files[0];
var fileName = Path.GetFileName(fileData.FileName);
var fileSavePath = Server.MapPath("~/upload/" + fileName);
GameName=Request["formName"];
Gamefile=fileName;
if (IsPost) {
var isValid = true;
if (Gamefile.IsEmpty()){
fileerrorMessage = "Please upload a file.";
isValid = false;
}
else if (GameName.IsEmpty()){
NameerrorMessage = "Please give the game a name.";
isValid = false;
}
if (isValid){
fileData.SaveAs(fileSavePath);
var SQLINSERT = "INSERT INTO Games (Name, file_path) " + "VALUES (#0, #1)";
db.Execute(SQLINSERT, GameName, Gamefile);
Response.Redirect("default.cshtml");
}
else
{
<p class="message error">Please correct the errors and resubmit the form.</P>
}
}
}
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file" />
#if(!fileerrorMessage.IsEmpty()) {
<label for="file" class="validation-error">
#fileerrorMessage
</label>
}
<p><input type="text" name="formName" value="#GameName" />
#if(!NameerrorMessage.IsEmpty()) {
<label for="file" class="validation-error">
#NameerrorMessage
</label>
}
<input type="submit" value="Add Game" />
</form>
The error is apparently with line 12. which means there should be something wrong with: var fileData = Request.Files[0];
If you try to reference Request.Files by index when there are no files uploaded, you will get this error. Your code runs when the page first loads, so the user has had no chance to upload a file, which means Request.Files is bound to be empty.
Move if(IsPost) up above your declaration for fileData and check the count of Request.Files before attempting to reference anything in it:
if(IsPost){
if(Request.Files.Count > 0){
var fileData = Request.Files[0];
var fileName = Path.GetFileName(fileData.FileName);
var fileSavePath = Server.MapPath("~/upload/" + fileName);
//etc