Selenium: select first inner element - html

I select all <a> elements inside all <td> elements
<td class="thread">
<i class="ter green"></i>
Something about...
<p class="info">Author</p>
</td>
I use the following:
driver.findElements(By.cssSelector("td.thread a"));
However, I'm getting much more elements than there should be. I guess that I must select only first a inside td class="thread". How can I do that?

When you use the CSS Selector td.thread a, that reads any descendant a under td.thread. What you more likely want is td.thread > a which reads a child a of td.thread. It's still possible there are more than one a but you will likely get a lot fewer depending on the overall HTML.
CSS Selector reference

thread = driver.find_element_by_class_name('thread')
correct_link = thread.find_element_by_tag_name('a').get_attribute('href')
print(correct_link)
>>> "/forum/threads/12/"

Related

CSS solution to make parent invisible when all children are invisible

I'm looking to hide an element platform-group based on whether it has any visible job-btn children. If all the children are hidden, then I'd like to hide the parent.
So if I have HTML showing like this:
B R( C J ) HideMe( )
I would like it to show like this:
B R( C J )
A JS fiddle with this is here: http://jsfiddle.net/cheshirecam/wf60z08n/5/
The HTML:
<tr>
<span style="display: inline-block;" class="job-btn">B</span>
<span style="display: inline;" class="platform-group">R(
<span style="display: inline-block;" class="job-btn filter-shown">C</span>
<span style="display: inline-block;" class="job-btn filter-shown">J</span>
<span style="display: none;" class="job-btn">V</span>
</span>
<span style="display: inline;" class="platform-group">HideMe(
<span style="display: none;" class="job-btn">C</span>
<span style="display: none;" class="job-btn">J</span>
</span>
</tr>
CSS:
.platform-group::after {
content: ")";
}
B, C and J are different job codes. C and J are in the platform-group of R. The platform-group of "HideMe" has no visible jobs, so I'd like it to hide itself.
A job gets the filter-shown class added/removed and the display: none or inline-block depending on some complex filter parameters the user can set. When I do that check, I could add or remove anything from the element. Adding/removing a class seems slow, and data values seem slow, too. Is there something better to tag the element with that the parent can detect somehow? Something that works kind of like this seems so close: https://developer.mozilla.org/en-US/docs/Web/CSS/:empty
I have this working using jQuery to check if the parent has 0 descendents jobs with the .filter-shown class and then hiding it.
The trick is, I'm doing this thousands of times on the page (it's a test-result dashboard of extra-ordinary magnitude) I would like a CSS only (or at least mostly) solution. The problem is it's kind of slow when turning filtering on and off. Profiling shows that adding/removing the filter-shown class is fairly expensive for each job.
I'm not above rearranging the HTML to make this work, as long as it looks roughly the same visually. Any thoughts or ideas on good directions to try are most appreciated.
Rather than adding classes suppose, in the Javascript/jQuery, you add the child spans you want shown by setting the innerHTML of the parent? Then, if there were no spans added, the parent element would be truly empty, and you could then use :empty, as in:-
platform-group:empty {
display : none;
}

Using XPath 1.0 with HTML to match elements that aren't in a parent

Consider this HTML:
<div>
<table>
<tr>
<td>
<a class="cal-date">1</a>
<div class="checkin-time">6 AM | 8h 30m</div>
</td>
</tr>
</table>
</div>
I would like to use XPath 1.0 to return 6 AM | 8h 30m while matching the class (cal-date) and text contents (1) in <a class="cal-date">1</a>. The <a> isn't a parent or anything, so I'm a little lost.
How is this done?
XPath has the concept of axes (that’s plural of axis, not things for cutting down trees). The default axis is the child:: axis, so if you don’t specify it your query will be searching the children of the previous node. You can create more complex queries by using different axes.
In this case you probably want to use the following-sibling:: axis. First select a element as usual, then in the next location step of your query specify the following-sibling:: axis to search the siblings of the a node rather than its children:
//a[#class='cal-date' and . = '1']/following-sibling::div
If you need to you can be more specific with the div query, as with “normal” XPath, and can continue the query after the change of axis. For example if your HTML was more complex and looked like this:
<a class="cal-date">1</a>
<div>A decoy div</div>
<div>
<span>Not this</span>
<span class="checkin-time">6 AM | 8h 30m</span>
<span> Not this either</span>
</div>
you could get at the checkin-time span with an XPath expression like this:
//a[#class='cal-date' and . = '1']/following-sibling::div[2]/span[#class='checkin-time']
Note that when selecting the span element, after the following-sibling::div part, the axis isn’t specified so it uses the default of child::, because we are looking for children of the div.
There's no need to use following-sibling for this. Alternatively, search for <div/> elements contained by table cells which contain the link you're looking for.
//td[a[#class='cal-date' and . = '1']]/div

It seems impossible to have 2 blank lines between p tags Without modification of the original elements

Here is another for my previous question:
Is it impossible to have 2 blank lines between p tag? Markdown
After various comments given, I once thought I can manage it;
in fact, I cannot.
--------
br
--------
AB
--------
p tag
--------
A
B
--------
OK, now, I want to insert 2 lines instead of 1 between A and B elements without any modification of the original elements;
The result I expect is like this (br emulation)
--------
AB
--------
trying with p tag
--------
A
B
--------
Ouch!! 3 lines inserted instead of 2.
so, is there no way to do this by HTML and CSS??
The code:
http://jsfiddle.net/LhDFs/9/
--------<br>
## br<br>
--------<br>
A<br>B
<br>--------<br>
## p tag
<br>--------
<p>A</p>
<p>B</p>
--------<br>
## OK, now, I want to insert 2 lines instead of 1 between A and B elements without any modification of the original elements;<br>
## The result I expect is like this (br emulation)
<br>--------<br>
<br>
A<br><br><br>B
<br>
<br>--------<br>
## trying with p tag
<br>--------<br>
<p>A</p>
<p style = 'margin: 0;'> </p>
<p>B</p>
--------<br>
## Ouch!! 3 lines inserted instead of 2.
<br> ## so, is there no way to do this by HTML and CSS??
Edit:
some people mention that my understanding to HTML is immature, well I won't deny it; however, what people said is about HTML restriction.
To make things clearer, this is for HTML+js coding, not static. So, again I want to insert 2 (or any number ) lines instead of 1 between A and B elements without any modification of the original elements;
Because the function is not to modify the original context but to insert blank lines. What I intend is to insert things. When I insert things, if I need to modify the original context, more complicated and things generally don't go well. So, if it is really impossible to insert exact lines between original elements, I gave up and make a mess to modify original context. What I would like to know is if it's possible or impossible.
If it's really impossible, just tell me so instead of giving me some codes.
Thank you.
Edit:
I conclude it is not possible to insert the exact lines as long as the default paragraph tag context exists.
So, instead, the whole context should be constructed with 'noMargin' paragraph tag.
http://jsfiddle.net/LhDFs/10/
<p class="noMargin">No margin</p>
<p class="noMargin"> </p>
<p class="noMargin"> </p>
<p class="noMargin">No margin</p>
css
p.noMargin {
margin: 0;
} 
or simply
<p>No margin</p>
<p> </p>
<p> </p>
<p>No margin</p>
css
p{
margin: 0;
} 
The credit goes to
#3dgoo
Is it impossible to have 2 blank lines between <p> tag? Markdown
Thank you everyone, and if someone had unpleasant feelings on my post, my apologies.
I will show you the Right Way to do it. Which is very easy to understand, improve upon, and modify in future.
http://jsfiddle.net/techsin/FDK7P/
Oh and css is not javascript
css code .double-space {margin-top:2em;} then apply class attribute to whatever paragraph you want to have double space. But if you want to do it the first way i did it, using pseudo selectors, then it's fine but more work and inefficient.
But there is a way to do it other ways...
http://jsfiddle.net/techsin/FDK7P/1/
I recommend the first way of doing it...because look at pictures below
Css Styles in gray are applied by browser automatically/default values for or block elements.
So therefore we make 1em to 2em for whichever paragraph we want to modify. Which overrides the default value of 1em.
Ok, let's get back to html basics, probably it'll help!
First of all, a p tag is a block element that contains inline elements.
Short tutorial here: http://www.webdesignfromscratch.com/html-css/css-block-and-inline/
So p is a paragraph, and br means a line breaks. In fact, you divides your content in paragraph, and sometimes your need to change line with line breaks. If you want to have, lets say:
text A
text B
Then you should have two different paragraphs:
<p style="margin-bottom: 1em;">text A</p>
<p>text B</p>
(ok, put you css in a different file, not inline)
The margin push the other paragraph. For line breaks, it should look like this:
text A
text B
<p>text A<br>text B</p>
I keep the paragraph around all, but a line break in it.
And applying margin-bottom to p in css, all your paragraph will have the same distance! A bit like the style thing with normal, header 1, header 2... in Word where you can decide margin before and after.
Hope it helps!
EDIT:
You can do it with Javascript, or I prefer to use jQuery that way:
(in jQuery coding)
$('p').each(function() {
var $this = $(this);
if ($this.html() == ' ') {
$this.remove();
}
});
You can use regex, for example. I removed the p tag containing the non breaking space because it add a full paragraph between. Keep two different paragraph so it will be easier to put some margins and control everything with css (like I said a the top of my answer. Don't try to add br or p between, but margins!). With br, you need 3 br to skip two lines between.
Is that what you need? If not, please be more clear!
You 'see' three lines because the A and B paragraphs (p elements) add up their own margin. You need to style those elements to achieve what you need.
Something like this (obviously is better to use css classes instead of style attribute:
<p style='margin: 0;'>A</p>
<p style='margin: 0;'> </p>
<p style='margin: 0;'>B</p>
Try to style it like one of these
<p style="margin-bottom: 10px;">text</p>
<p style="line-height: 200%;">text</p>
A line height in percent of the current font size

XPath selecting explicit element comparing on value

This is what I have tried so far..
//div[#id='information']//div[div=='Site']
//div[text()='Site']//span//a[#href]
I am fiddling with an XPath expression but it´s not working out. I want to select the anchor's href attribute. Thats no problem but it needs to be explicitly after a div with class h3 AND a value = "Site".
<div id="information">
<div class="h3">Location</div>
<div class="h3">Site</div>
<span>
//Here is sometimes a <br/>
<a href='http://www.test.at'>Klick</a>
</span>
<div class="h3">Referenz</div>
<span>12345</span>
</div>
There can be arbitrarily many div elements inside the div with id="information" so selecting on index is not possible.
Something like this should work:
//div[#class = 'h3'][. = 'Site']/following-sibling::*/descendant-or-self::a/#href
This will extract the href attributes of all a tags that are after the "Site" div in document order but still contained within the same parent element (the "information" div in your example). If you're not bothered about that last bit, i.e. you want to include a tags that occur after the "information" div as well as inside it, then you can use the simpler
//div[#class = 'h3'][. = 'Site']/following::a/#href

How do I Align three spans using CSS (no tables)

I have this table in some code;
<table>
<tr><td align="left">One</td><td align="center">Two</td><td align="right">Three</td>
<tr><td align="left">One</td><td align="center">Two</td><td align="right">Three</td>
<tr><td align="left">One</td><td align="center">Two</td><td align="right">Three</td>
</table>
I would like to not use tables and do the alignment and such all in CSS. I tried;
<span style="float:left;">One</span><span style="margin-left:auto;margin-right:auto;">Two</span><span style="float:right;">Three</span>
<span style="float:left;">One</span><span style="margin-left:auto;margin-right:auto;">Two</span><span style="float:right;">Three</span>
<span style="float:left;">One</span><span style="margin-left:auto;margin-right:auto;">Two</span><span style="float:right;">Three</span>
Example would be trying to convert this data to CSS to align as the table would;
<table>
<tr><td align="left">Bob</td><td align="center">Dingle</td><td align="right">3923.33</td></tr>
<tr><td align="left">Johann</td><td align="center">Strauss</td><td align="right">33.33</td></tr>
<tr><td align="left">Skip</td><td align="center">Skipperson</td><td align="right">0</td></tr>
</table>
But the text in the middle doesn't align correctly as its jagged (different lengths) and so are the left and right values. Seems this is madness and I am leaning towards "Just Use Tables".
First, get your HTML right: Use the correct tags to contain your data. The information you gave isn't really enough for us to ascertain what type of information you're trying to format. If it is tabular data, then there's no shame in using tables - its what its meant for.
Now the correct manner to using CSS is not to place all of your styles inline like what you are doing. Keep them in a separate CSS file instead, and use selectors to avoid having to repeat yourself so many times.
Here's the solution: http://www.jsfiddle.net/2TDXc/
Oh, and please don't listen to that 'Just Use Table' bullcrap. Really, its better for everyone in the long run.
What do you mean jagged? You mean you want text-align:justify ? Or do you mean you're having trouble with the columns being different heights? If the latter, containing divs might help. For that matter, try using divs instead of spans or setting display:block
Anyway, looking at the CSS templates provided by Matthew James Taylor may help if you mean the latter problem.
You need to make use of the display:inline and display:inline-table css attributes. They're great for forcing any element to sit next to each other on the same line.
<div>
<span style="display:inline-table;padding:2px;">One</span><span style="display:inline-table;padding:2px;">Two</span><span style="display:inline-table;padding:2px;">Three</span><br />
<span style="display:inline-table;padding:2px;">One</span><span style="display:inline-table;padding:2px;">Two</span><span style="display:inline-table;padding:2px;">Three</span><br />
<span style="display:inline-table;padding:2px;">One</span><span style="display:inline-table;padding:2px;">Two</span><span style="display:inline-table;padding:2px;">Three</span><br />
</div>
As for the jagged-ness, you must realize that your columns do not inherit or share anything from each other like they would in a table, so you'll ultimately have to hardcode a width. It looks like a table might be what you need.