Xdocument,Descendants in C# - c#

I have the below code to get alexa page rank.
private int GetAlexaRank(string domain)
{
var alexaRank = 0;
try
{
var url = string.Format("http://data.alexa.com/data?cli=10&dat=snbamz&url={0}", domain);
var doc = XDocument.Load(url);
var rank = doc.Descendants("POPULARITY").Select(node => node.Attribute("TEXT").Value).FirstOrDefault();
if (!int.TryParse(rank, out alexaRank))
alexaRank = -1;
}
catch (Exception e)
{
return -1;
}
return alexaRank;
}
But I truly don't understand how does that code work???
Would you tell me exactly, what is the "POPULARITY" and "TEXT"? and where are they stored?
I don't understand this syntax: doc.Descendants("POPULARITY").Select(node => node.Attribute("TEXT").Value).FirstOrDefault();
Please!!!!

I would recommend you navigating to the url you have in your code and take a look at the XML file structure. You should see tags with POPULARITY and TEXT, by the look of your code these are the nodes/attributes/values that you are selecting.
.Descendants returns a collection, and since you provide POPULARITY it will bring back the elements within the <POPULARITY> tag in your XML file.
You are then looking at each node in the Collection whose Descendants are Popularity and selecting an item with attribute TEXT. Your return the first value found, or null if the collection does not contain a node with attribute TEXT.

Related

C# find a specific element with two or more xml files?

I try to explain my problem:
Okay, I need the KSCHL and the Info.
I need the KSCHL from the result file and then I want to search after the KSCHL in the other file "Data".
In the first file I have all KSCHL.
var kschlResultList = docResult.SelectNodes(...);
var kschlDataList = docData.SelectNodes(...);
var infoDataList = docData.SelectNodes(...);
for (int i = 0; i < kschlResultList.Count; i++)
{
string kschlResult = kschlResultList[i].InnerText;
for (int x = 0; x < kschlDataList.Count; x++)
{
string kschlData = kschlDataList[x].InnerText;
if (kschlData == kschlResult)
{
for (int y = 0; y < infoDataList.Count; y++)
{
string infoData = infoDataList[y].InnerText;
if (infoData == kschlResult)
{
//I know the If is false
string infoFromKschl = infoData;
}
}
}
}
}
The problem is now to find the KSCHL (from the first file) in the second file and then to search after the "info".
So if I have the KSCHL "KVZ1" in the first file, then I want to search this KSCHL in the second file and the associated Info for it.
Hope you understand :)
You don't have to loop quite so much. :-)
Using XPath - the special strings inside SelectNodes() or SelectSingleNode(), you can go pretty directly to what you want.
You can see a great basic example - several really - of how to select an XML node based on another node at the same level here:
How to select a node using XPath if sibling node has a specific value?
In your case, we can get to a list of the INFO values more simply by looping just through the KSCHL values. I use them as text, because I want to make a new XPath string with them.
I'm not clear exactly what format you want the results in, so I'm simply pushing them into a SortedDictionary for now.
At that last step, you could do other things as is most useful to you..... such as push them into a database, dump them in a file, send them to another function.
/***************************************************************
*I'm not sure how you want to use the results still,
* so I'll just stick them in a Dictionary for this example.
* ***********************************************************/
SortedDictionary<string, string> objLookupResults = new SortedDictionary<string, string>();
// --- note how I added /text()... doesn't change much, but being specific <<<<<<
var kschlResultList = docresult.SelectNodes("//root/CalculationLogCompact/CalculationLogRowCompact/KSCHL/text()");
foreach (System.Xml.XmlText objNextTextNode in kschlResultList) {
// get the actual text from the XML text node
string strNextKSCHL = objNextTextNode.InnerText;
// use it to make the XPath to get the INFO --- see the [KSCHL/text()= ...
string strNextXPath = "//SNW5_Pricing_JKV-Q10_full/PricingProcedure[KSCHL/text()=\"" + strNextKSCHL + "\" and PRICE>0]/INFO/text()";
// and get that INFO text! I use SelectSingleNode here, assuming only one INFO for each KSCHL..... if there can be more than one INFO for each KSCHL, then we'd need another loop here
string strNextINFO = docdata.SelectSingleNode(strNextXPath)?.InnerText; // <<< note I added the ? because now there may be no result with the rule PRICE>0.
// --- then you need to put this result somewhere useful to you.
// I'm not sure what that is, so I'll stick it in the Dictionary object.
if (strNextINFO != null) {
objLookupResults.Add(strNextKSCHL, strNextINFO);
}
}

Find an element with Selenium Webdriver which fulfils multiple By-criteria

I am using v2.52 of Selenium and the WebDriver with C#. What I am trying to achieve should be fairly simple, but I am unable to find the solution for: I'd like to find an element by multiple By-criteria.
Let's say, I have something like this:
Click me!
Click me!
<p class="foo">Click me!</p>
Ignore the fact, that I could use By.CssSelector, By.CssSelector, By.XPath and so on. I was assuming that it should be possible to do something like this:
driver.FindElement(By.TagName("a").ClassName("foo"))
// ...or something like this...
driver.FindElement(By.TagName("a"), By.ClassName("foo"))
OpenQA.Selenium.Support.PageObjects.ByChained does not do the trick, since it is searching hierarchical.
Is there a way to find element(s) which match multiple By-criteria?
Best regards,
Carsten
I imagine something like this may work for your case:
public IWebElement FindElementByMultipleCriteria(List<By> Criteria, IReadOnlyCollection<IWebElement> toFilter = null)
{
// If we've reached the end of the criteria list, return the first element:
if (Criteria.Count == 0 && toFilter != null) return toFilter.ElementAt(0);
// Take the head of the criteria list
By currentCriteria = Criteria[0];
Criteria.RemoveAt(0);
// If no list of elements found exists, we get all elements from the current criteria:
if (toFilter == null)
{
toFilter = Driver.FindElements(currentCriteria);
}
// If a list does exist, we must filter out the ones that aren't found by the current criteria:
else
{
List<IWebElement> newFilter = new List<IWebElement>();
foreach(IWebElement e in Driver.FindElements(currentCriteria))
{
if (toFilter.Contains(e)) newFilter.Add(e);
}
toFilter = newFilter.AsReadOnly();
}
// Pass in the refined criteria and list of elements found.
return FindElementByMultipleCriteria(Criteria, toFilter);
}
IWebElement example = FindElementByMultipleCriteria(new List<By>(){ By.TagName("a"), ClassName("foo") });
Essentially, you're taking the list of elements found by the first By passed in. You are then going through the remaining By criteria and removing elements from that initial list that are never found again.
This is horribly inefficient and I don't really understand why you would want to do this, but it exists.
Oh also, you'll need to add using System.Linq; in order to interact with the IReadOnlyCollection.
Well I think you can try something like this, and let me know if it works:
public IWebElement FindElementUsingNestedBy(By firstCriteria, By secondCriteria)
{
var allElements = Driver.FindElements(firstCriteria);
foreach (var webElement in allElements)
{
try
{
var desiredObject = webElement.FindElement(secondCriteria);
return desiredObject;
}
catch (NotFoundException ex)
{
}
}
return null;
}

Geckofx get specific links from a page

var links = new List<GeckoElement>();
foreach (var link in geckoWebBrowser1.Document.Links)
{
if (!String.IsNullOrEmpty(link.GetAttribute("href").ToString()))
links.Add(link);
}
}
I have this code to collect all links in the page, but I cant figure it out how can I filter to some specific links that starts with for example "ow.ly". Rest in the list should be ignored.
Tryed this but didnt seem to work
if (links.Count > 0)
{
if (links.Equals("ow.ly"))
{
}
}
When I debug if links equals ow.ly it shows 0 reults.
links is a a List<GeckoElement>. So it’s unlikely that the list equals to the string "ow.ly". Instead, you want to filter the list for items, which href property contains that text.
You could do that for example like this:
var owlyLinks = geckoWebBrowser1.Document.Links.Where(link =>
{
string hrefAttribute = link.GetAttribute("href").ToString();
return !string.IsNullOrEmpty(hrefAttribute) && hrefAttribute.Contains("ow.ly");
}).ToList();
You might want to adjust the check so that "ow.ly" needs to appear somewhere special instead of just somewhere inside the string. For example, you could parse the whole Url, and then check that the host name equals to ow.ly.

How to find multiple elements on a page in selenium?

I have multiple input HTML tags on same page having same id and name or class,
Now How should I find 2nd or 3rd.. etc input. I can work with arrays so Do we have some function which will return all the textBox(input tag) from that page.
First you create a list with FindElements, then you can iterate through that list. For example:
var allTextBoxes = driver.FindElements(By.TagName("input"));
foreach(var textBox in allTextBoxes)
{
textBox.DoSomething();
}
You can use a for-loop as well:
for(int i = 0; i < allTextBoxes.Count; i++)
{
allTextBoxes[i].DoSomething();
}
Or if you want a specific Element, in example the 3rd:
allTextBoxes[2].DoSomething();
Expanding on Anaxi's answer,
If you are using the PageObject framework you can do it like this and set the FindsBy attribute on a property:
[FindsBy(How = How.Id, Using = "YourId")]
public IList<IWebElement> ListOfWebElements { get; set; }
i dont know about selenium... but to select element of html page you can use HtmlAgilityPack..
HtmlWeb hw = new HtmlWeb();
HtmlDocument doc = hw.Load(#"http://example.com");
HtmlNode node = doc.DocumentNode.SelectNodes("//div[#class='your_class_name']");
it will return a list of node that contains your_class_name.. then find and use the one you want.
to select all the input tags from that page you can use
foreach (var input in doc.DocumentNode.SelectNodes("//input"))
{
//your logic here
}
hope it helps..
In C# I use FindElements then ElementAt():
var foo= Driver.FindElements(By.XPath("//div[#class='your_class_name']"));
var foo2= foo.ElementAt(1);
If it's 10 elements with the same ID (which is HORRIBLE) and I'd like to grab the 8th element, I just use ElementAt(8); (or index 7 or however you're set up).
It's a tough call. I'd much rather have them fix the code but in some cases that's just not going to happen... at least not in the near future.
Hope this helps.

Getting ALL attributes from an IWebElement with Selenium WebDriver

I want to extract some information from the DOM with Selenium. I'm using the C# WebDriver.
Looking at the IWebElement interface you can easily extract a given attribute. However, I would like to extract all the attributes of an element without knowing their names in before hand.
There must be some simple way of doing this since there is a method for getting an attribute value if you know its name.
An example:
<button id="myButton" ng-click="blabla()" ng-show="showMyButton"
some-other-attribute="foo.bar" />
IWebElement element = driver.FindElement(By.Id("myButton"));
Dictionary<string, string> attributes = new Dictionary<string, string>();
// ???????
// Profit.
Hopefully I'm missing something obvious.
Thanks in advance!
The .attributes property in JavaScript will return an array of all the attributes a given element has and it's value.
So what you'll need to do is first get a driver that has the capability to run JavaScript:
IJavascriptExecutor javascriptDriver = (IJavaScriptExecutor)driver;
Now, execute it by:
Dictionary<string, object> attributes = javascriptDriver.ExecuteScript("var items = {}; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;", element) as Dictionary<string, object>;
The idea behind the JavaScript is to use the JavaScript attributes property within the element itself and then pull out the information we need - the name and value of the attribute. The attributes property, in reality, pulls a lot of information about each individual property but we want only two fields. So we get those two fields, put them into a dictionary and WebDriver will then parse it back to us. (It could probably be cleaned up a bit)
It's now a Dictionary and thus you can loop through however you like. The key of each pair will be the name of the attribute, and the value of each pair will be the value of the attribute.
Only tested this with a few elements dotted around the web (here, Google, and a few small web pages) and it seems to work well.
You can try this:
IWebElement element = driver.FindElement(By.Id("myButton"));
string elementHtml = element.GetAttribute("outerHTML");
This will give you the html of the element. From here, you can parse it, as Arran suggested
List<IWebElement> el = new List<IWebElement>(); el.AddRange(driver.FindElements(By.CssSelector("*")));
List<string> ag= new List<string>();
for (int b = 0; b < el.Count; b++)
{
ag.Add(el[b].GetAttribute("outerHTML"));
}
you can do a FindElement(By.tag("body")) to return a list of WebElements and then parse the results as you suggest.
You can try this:
Actions newTab = new Actions(web driver);
newTab.ContextClick(element).SendKeys(Keys.ArrowDown).SendKeys(Keys.ArrowDown).SendKeys(Keys.Return).Build().Perform();
I have created WebDriver Extension based on the first answer
public static List<string> GetElementAttributes(this RemoteWebDriver driver, IWebElement element)
{
IJavaScriptExecutor ex = driver;
var attributesAndValues = (Dictionary<string, object>)ex.ExecuteScript("var items = { }; for (index = 0; index < arguments[0].attributes.length; ++index) { items[arguments[0].attributes[index].name] = arguments[0].attributes[index].value }; return items;", element);
var attributes = attributesAndValues.Keys.ToList();
return attributes;
}

Categories