Access the sibling nodes from current node in XPath - xpath

<div class="form-group value">
<label>Text
<a href="#" class="">
<span class="glyphicon glyphicon-pencil"></span>
</a>
</label>
<div>
<input/>
</div>
</div>
Can we access the span element with the class glyphicon glyphicon-pencil from input element.

One of the simplest way maybe using preceding axis which will find previous elements relative to current context element regardless of the parent/level (I assume that the current context element here is the <input/> element) :
preceding::span[#class='glyphicon glyphicon-pencil']
contrasts with preceding-sibling axis which only match previous element within the same parent (in other words, previous element at the same level).

Related

How to make parent div activate styling of child div for hover and active

I made this style for side bar navigation
I made a box and used transform to hide it on the left side, to get the curved border effect.
On hover, active ect
Border button -> bg-green-300
text-green-300 for icon and text
font-semibold for text only
<a href="/dashboard">
<div class="flex flex-row space-x-8 w-72 text-lg pb-3 text-gray-200">
<div class="h-8 w-8 rounded transform -translate-x-7 hover:bg-green-300"></div>
<div class="flex flex-row items-center space-x-8 transform -translate-x-10 -translate-y-1">
<i class="bi bi-columns-gap hover:text-green-300 transform translate-x-1"></i>
<h2 class="hover:font-semibold hover:text-green-300 transform translate-y-1 text-base">Dashboard</h2>
</div>
</div>
</a>
Is there something I can add to the main div to activate the hover effect in each child element at same time?
Right now it works only when I hover over each individual element.
Any help is much appreciated :)
Use group-hover state
Add group class to your parent element (anchor-tag in your case)
Replace hover: with group-hover:
Worth to mention not every property supports group-hover, so there can be situation, where you may need to extend core plugins. More info about group-hover here
DEMO https://play.tailwindcss.com/dzacJTR76X
Use group in parent and group:hover in child
Code Structure:
<div class="group">
<div class="group-hover:... "/>
<div class="group-hover:... "/>
</div>
Example:
<div class="group flex ">
<div class="rounded-full bg-black w-10 h-10 group-hover:bg-cyan-400 "></div>
<i class="text-4xl ml-4 group-hover:bg-cyan-400 cursor-pointer ">Brighten me</i>
</div>
Output:
OnHover:

Get Element using XPath in Puppeteer

I am trying to scrape multiple elements with the same class names but each has a different number of children. I am looking for a way to select specific elements using the xpath(this would make it easiest for my loop).
const gameTimeElement = await page.$$('//*[#id="section-content"]/div[2]/div[1]/div/div['+ i + ']');
const gameTimeString = await gameTimeElement[j].$eval('h3', (h3) => h3.innerHTML);
This currently does not work.
After I select the element, I grab the h3 tag inside and evaluate it to get the innerHTML.
Is there a way to do this utilizing xpath?
<div id="section-content" style="display: block;">
</div>
<div class="matches">
<div class="day day-28-1" data-week="1" style="display: block;">
<h4>Sat, March 28, 2020</h4>
<div class="day-wrap">
<div class="match region-7-57d5ab4-9qs98v" data-week="1">
<h3 class="time">2:00PM
<span>(Central Daylight Time)</span>
<span class="fr">Best of 7</span>
</h3>
<div class="row ac ">
<div class="col-xs-3 ar">
<img class="team-logo" src="url"></div>
<div class="col-xs-2 al">
<h4 class="loss">(NA)<br>
<span class="team-name">Team1</span>
<br>
<span class="win spoiler-wrap">0</span>
</h4>
</div>
<div class="col-xs-2">
<img class="league-logo" src="url">
<h4> V.S.</h4>
</div>
<div class="col-xs-2 ar">
<h4 class="">(NA)<br>
<span class="team-name">Team2</span>
<br>
<span class="win spoiler-wrap">4</span>
</h4>
</div>
This is a sample of what I am working with for HTML on the website.
Yes, div class="day-wrap" could have a different number of childs. But I don't think that's a problem.
You want to get game times of all Rocket League matches. As you've noticed, games times are located within h3 elements. You can access it directly with one of the following XPaths :
//div[#id="section-content"]//h3
//div[#class="day-wrap"]//h3
//div[contains(#class,"match region")]//h3
If you want something for a loop then you can try :
(//div[#class="day-wrap"]//h3)[i]
where i is the number to increment (from 1 to x).
Side notes : your sample data looks incorrect (according to your XPath). You have a closing div line 2 and it seems you omit div class="row middle-xs center-xs weeks" before div class="matches".

How to select a neighboring html element with xpath?

I have a html source in which several input boxes are defined as follows:
<div class="jupyter-widgets widget-hbox widget-text" style="">
<div class="widget-label" style="display: block;">Project:</div>
<input type="text" class="form-control" placeholder="">
</div>
<div class="jupyter-widgets widget-hbox widget-text" style="">
<div class="widget-label" style="display: block;">Title:</div>
<input type="text" class="form-control" placeholder="">
</div>
...
How do I select the input element associated with the Project element?
This should work:
//div[contains(text(), "Project")]/following-sibling::input
First part //div[contains(text(), "Project")] will find the div element which has "Project" in text attribute, then /following-sibling::input will find the input type sibling of that div element.
Read more about these xpath functions here.
You can use something like: "//input[#type='text'][1]" or "(//input[#type='text'])[1]". Respectively the number represents the element you are looking for. Hope it helps.

Select span for select2 using Capybara

I'm trying to write a custom method that allows me to use our custom select2 country_search element. The elements are a bit wonky, but the snippet of HTML looks like this:
<div class="control-group select optional admins_customer_form_object_country_id">
<label class="select optional control-label" for="admins_customer_form_object_country_id">Country</label>
<div class="controls">
<select id="admins_customer_form_object_country_id" class="select optional select2-hidden-accessible" name="admins_customer_form_object[country_id]" tabindex="-1" aria-hidden="true">
<option value=""></option>
<option value="true">Yes</option>
<option value="false">No</option>
</select>
<span class="select2 select2-container select2-container--classic select2-container--below select2-container--focus" dir="ltr" style="width: 220px;">
<span class="selection">
<span class="select2-selection select2-selection--single" role="combobox" aria-autocomplete="list" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-labelledby="select2-admins_customer_form_object_country_id-container">
<span class="select2-selection__rendered" id="select2-admins_customer_form_object_country_id-container">
<span class="select2-selection__placeholder">Select Country</span>
</span>
<span class="select2-selection__arrow" role="presentation">
<b role="presentation"></b>
</span>
</span>
</span>
<span class="dropdown-wrapper" aria-hidden="true"></span>
</span>
</div>
</div>
I wrote a helper that should select the correct span and perform a click on it, but I'm stuck selecting the span I want. I'm trying to select the outer visible span which has class select2 select2-container select2-container--classic select2-container--below select2-container--focus but I keep getting invalid XPath errors.
This is what I have so far:
def select_country(label:, value:)
# Select our label first
label_element = first("label", text: label)
# Now navigate through the entire tree, and click the correct SPAN element.
within(label_element) do
select2_container = find(:xpath, "..") # Up one level to the parent div
select2_container = select2_container.find("div.controls") # Down one level into the div.container
select2_container = select2_container.find(:xpath, "./*[1]") # select the span element surrounding all.
end
end
With the last line I can select the select element from the tree, but I can't get the span sibling whatever I try.
If I'm reading correctly you want the span that is the child of div.controls, replacing the last two finds with the following should do that
select2_container = select2_container.find('div.controls > span')
You can add classes to the span in the css selector if needed but in your html it's the only span child so it's not necessary

XPath to look for subtree

I'm scraping an html document, whose structure changes all the time. Css class names even change, so I can't rely on that. However, one thing never changes, the value is always contained in a subtree exactly like the following:
<span>
<span>
<span>wanted value</span>
<span></span>wanted value
</span>
</span>
Can this be expressed as an XPath expression?
It should not match:
<span>
<span>
<span> 1, one too little </span>
<span> 2 </span>
<span> 3, one too many </span>
<span> 4, two too many </span>
</span>
</span>
I plan to do this using lxml for Python.
If the location of the wanted value is always on the third level of span an xpath as follows will work:
//span/span/span[1]
When applied on the next HTML document:
<html>
<head>
<title>Your Title</title>
</head>
<body>
<div>
<span>
<span>
<span>wanted value</span>
<span></span>
</span>
</span>
</div>
<div>
<span>
<span>
<span>wanted value</span>
<span></span>
</span>
</span>
</div>
</body>
</html>
The result will be:
wanted value
wanted value
EDIT
If you only want the values of the first span on the third level when the total of spans equals 2 on the third level you can use the following XPath:
//span/span[count(span) = 2]/span[1]

Resources