Thymeleaf check box checked using two string collection - spring

I have two string collection.
One is to generate all check boxes.
The other one is to select the element to check.
For example, I have two string collections
["A", "B", "C", "D"]
["A", "C"]
I want to make 4 check boxes A, B, C, D
and want to check A and C
I tried as below.
<span th:each="interestName : ${allInterest}">
<span th:each="interest : ${userInfo.interestName}">
<input type="checkbox"
name="eachUserInterest"
th:value="${interestName.name}"
th:checked="${interestName.name.equals(interest)}"/>
<label th:text="${interestName.name}"></label>
</span>
</span>
However, above code generates a check box repeatedly as many times as it is checked.
Execution Results
Help me, please.

You should just loop over the allInterest array, and use contains to determine whether or not the checkbox is checked. Something like this for example:
<th:block th:each="interest: ${allInterest}">
<input type="checkbox"
name="eachUserInterest"
th:value="${interest}"
th:checked="${userInfo.interestName.contains(interest)}" />
<label th:text="${interest}"></label>
</th:block>

Related

How can I wrap a div around existing elements?

I'm trying to parse an existing document and modify it by wrapping a div around some existing form elements.
HTML form looks a bit like this:
<form>
<label for="username">Username:</label>
<input name="username" type="text" />
<label for="password">Password:</label>
<input name="password" type="password" />
</form>
I can parse the document OK with Nokogiri and i'm aware of the wrap method but i'm struggling to grasp how to select both the label and input tags in one go and then wrap a div around these. So the result I am looking for is:
<form>
<div class="form-group">
<label for="username">Username:</label>
<input name="username" type="text" />
</div>
<div class="form-group">
<label for="password">Password:</label>
<input name="password" type="password" />
</div>
</form>
I have tried various XPaths / CSS selectors and can create a nodeset of just labels/inputs or all of the elements of the whole form. Is there any way to achieve this modification?
A single XPath expression can only return a single collection of nodes, so in order to achieve what you want you will need to make several queries, one for each label – input pair.
You can select an individual pair with something like this, assuming the markup is well behaved (i.e each input has a label before it):
//label[1] | //label[1]/following-sibling::input[1]
This will select the first label and the following input. However you want to select all such pairs. One way would be to first select all the label nodes, and then for each label select it and the following input.
labels = doc.xpath("//form/label")
labels.each do |l|
nodes = l.xpath(". | ./following-sibling::input[1]")
# nodes now contains a label-input pair...
end
I don’t think the wrap method will work to add a div element as an ancestor to each pair, as it will add the element to each member of the nodeset. You will probably have to move them manually, something like
labels = doc.xpath("//form/label")
labels.each do |l|
# Select this node and its neighbour.
nodes = l.xpath(". | ./following-sibling::input[1]")
# Create the new element, and add it before the label.
div = Nokogiri::XML::Node.new('div', l.document)
l.before(div)
# Move each of the pair onto this new element.
nodes.each do |n|
div.add_child(n)
end
end
Note that this method doesn’t move any text nodes, so you may find the whitespace of your document changes a bit.

How to check box in Capybara if there are no name, id or label text?

I am newbie here. Please advise. How to select checkbox in my case?
<ul class="phrases-list" style="">
<li>
<input type="checkbox" class="select-phrase">
<span class="prase-title"> Dog - Wikipedia, the free encyclopedia </span>
(en.wikipedia.org)
<div class="prase-desc hidden">The domestic dog (Canis lupus familiaris or Canis familiaris) is a domesticated...</div>
</li>
The following doesn't work for me:
When /I check box "([^\"]+)"$/ do |label|
page.check(label)
end
step: And I check box "Dog - Wikipedia, the free encyclopedia"
If you can change the html, wrap the input and span in a label element
<ul class="phrases-list" style="">
<li>
<label>
<input type="checkbox" class="select-phrase">
<span class="prase-title"> Dog - Wikipedia, the free encyclopedia </span>
</label>
(en.wikipedia.org)
<div class="prase-desc hidden">The domestic dog (Canis lupus familiaris or Canis familiaris) is a domesticated...</div>
</li>
which has the added benefit of clicks on the "Dog - Wikipedia ..." text triggering the checkbox too. With that change your step should work as written. If you can't modify the html then things get more difficult.
Something like
find('span', text: label).find(:xpath, './preceding-sibling::input').set(true)
should work, although I'm curious how you're using these checkboxes from JS with nothing tying them to any specific value
Let's assume that you are prevented from changing the HTML. In this case, it would probably be easiest to query for the element via XPath. For example:
# Here's the XPath query
q = "//span[contains(text(), 'Dog - Wikipedia')]/preceding-sibling::input"
# Use the query to find the checkbox. Then, check the checkbox.
page.find(:xpath, q).set(true)
Okay - it's not as bad as it looks! Let's analyze this XPath so we can understand what it's doing:
//span
This first part says "Search the entire HTML document and discover all "span" elements. Of course, there are probably a LOT of "span" elements in the HTML document, so we'll need to restrict this:
//span[contains(text(), 'Dog - Wikipedia')]
Now we're only searching for the "span" elements that contain the text "Dog - Wikipedia". Presumably, this text will uniquely identify the desired "span" element on the page (if not, then just search for more of the text).
At this point, we have the "span" element that is adjacent to the desired "input" element. So, we can query for the "input" element using the "preceding-sibling::" XPath Axis:
//span[contains(text(), 'Dog - Wikipedia')]/preceding-sibling::input

Access two elements simultaneously in Nokogiri

I have some weirdly formatted HTML files which I have to parse.
This is my Ruby code:
File.open('2.html', 'r:utf-8') do |f|
#parsed = Nokogiri::HTML(f, nil, 'windows-1251')
puts #parsed.xpath('//span[#id="f5"]//div[#id="f5"]').inner_text
end
I want to parse a file containing:
<span style="position:absolute;top:156pt;left:24pt" id=f6>36.4.1.1. варенье, джемы, конфитюры, сиропы</span>
<div style="position:absolute;top:167.6pt;left:24.7pt;width:709.0;height:31.5;padding-top:23.8;font:0pt Arial;border-width:1.4; border-style:solid;border-color:#000000;"><table></table></div>
<span style="position:absolute;top:171pt;left:28pt" id=f5>003874</span>
<div style="position:absolute;top:171pt;left:99pt" id=f5>ВАРЕНЬЕ "ЭКОПРОДУКТ" ЧЕРНАЯ СМОРОДИНА</div>
<div style="position:absolute;top:180pt;left:99pt" id=f5>325гр. </div>
<div style="position:absolute;top:167.6pt;left:95.8pt;width:2.8;height:31.5;padding-top:23.8;font:0pt Arial;border-width:0 0 0 1.4; border-style:solid;border-color:#000000;"><table></table></div>
I need to select either <div> or <span> with id==5. With my current XPath selector it's not possible. If I remove //span[#id="f5"], for example, then the divs are selected correctly. I can output them one after another:
puts #parsed.xpath('//div[#id="f5"]').inner_text
puts #parsed.xpath('//span[#id="f5"]').inner_text
but then the order would be a complete mess. The parsed span have to be directly underneath the div from the original file.
Am I missing some basics? I haven't found anything on the web regarding parallel parsing of two elements. Most posts are concerned with parsing two classes of a div for example, but not two different elements at a time.
If I understand this correctly, you can use the following XPath :
//*[self::div or self::span][#id="f5"]
xpathtester demo
The XPath above will find element named either div or span that have id attribute value equals "f5"
output :
<span id="f5" style="position:absolute;top:171pt;left:28pt">003874</span>
<div id="f5" style="position:absolute;top:171pt;left:99pt">ВАРЕНЬЕ "ЭКОПРОДУКТ" ЧЕРНАЯ СМОРОДИНА</div>
<div id="f5" style="position:absolute;top:180pt;left:99pt">325гр.</div>

How to get parent's text using Nokogiri

I have situation where I want to get a parent <p> tag's text. For example:
<p>
<a name="TOPIC"></a>
<b><font color="#800000" size="4" face="Arial">Exapmles</font></b>
</p>
This is working fine for this example:
test = Nokogiri::HTML("row['test']"])
raw_attributes = test.root.css("p a").inject({}) do |accumulator, element|
accumulator[element.attr("name")] = (element.parent.text).strip
accumulator
end
But it's not working for the following example:
<p>
<font>
<a name="TOPIC"></a>
<b><font color="#800000" size="4" face="Arial">Exapmles</font></b>
</font>
</p>
How can I do this using Nokogiri? I want the solution which works for both of the above two conditions.
puts doc.at_xpath("//p[//a[#name='TOPIC']]").inner_text.strip
#=> "Exapmles"
Decoded, this says:
//p — find a p element anywhere in the document
[…] — that matches this condition
//a — it has an a element as a descendant
[#name='TOPIC'] — with a name attribute whose value is TOPIC.

Whats the best way to track the element occurrence and set a corresponding array in Ruby using Nokogiri

I am trying to scrape data from a website that contains both .value and .rating-ineligible classes mixed up.
I want to keep track of both .value and .rating-ineligible in a single array, to check whether .value is available or not:
page.css('td.title .value').text.strip
page.css('.rating-ineligible').text.strip
I want an array named FLAG[], with elements set as "A" when .value is present and "NA" if .rating-ineligible is present
where the output should look something like:
FLAG["A","A","A","NA","A","NA","A","A"]
Is there any hack that makes the FLAG array work?
Sample Input :
<td class=title>
<span class="rating-rating">
<span class="value">8.7</span>
</span>
<div class="rating-ineligible">
NYR
</div>
<span class="rating-rating">
<span class="value">5.2</span>
</span>
<span class="rating-rating">
<span class="value">6.1</span>
</span>
<span class="rating-rating">
<span class="value">7.9</span>
</span>
<div class="rating-ineligible">
NYR
</div>
<span class="rating-rating">
<span class="value">-</span>
</span>
<span class="rating-rating">
<span class="value">4.2</span>
</span>
</td>
If you see the Above Sample Input, there are three types of values present,
One is rating : *.*
Second is : NYR
Third one is : - (Hyphen)
I want these to be captured in a single array,
In which the value should be set as "A" if a valid rating is present in the format x.x
The value should be set as "NA" if the value present in the input is NYR.
and "-" if the Hyphen symbol - is present in the input.
Desired Output :
Flag ["A","NA","A","A","A","NA","-","A"]
Instead of setting flags i tired it by capturing the values into the below array,
r = page.css('td.title span.value').text.strip
noe=["NOE"]
ra=r.scan(/./)
ra.map!{|x| x=='-'?noe:x}.flatten!
rat=ra.join("")
rati=rat.scan(/.../)
And the output of the array rati[] looks like below,
rati ["8.7","5.2","6.1","7.9","NOE","4.2"]
But here the problem is,
There are totally 8 Values present in the given input,
out of which 5 values are in the format of x.x
one value is in the format of '-' which is captured as NOE in the array
But i am unable to capture NYR in that array.
Now desired output of the above input should look like this,
rati ["8.7","NYR","5.2","6.1","7.9","NYR","NOE","4.2"]
but I dont know the exact way, how to capture the NYR value into the array.
Can anyone gimme the right code to do this ?
Thanks in advance.
doc = Nokogiri::HTML(DATA.read)
result = doc.search("//td/*[starts-with(#class, 'rating-')]").map do |node|
case node.elements.first.text
when /\d+\.\d+/
'A'
when 'NYR'
'NA'
when '-'
'-'
end
end
pp result # ["A", "NA", "A", "A", "A", "NA", "-", "A"]

Resources