Thymeleaf URL Syntax is is confusing - spring-boot

So I'm trying to generate (dynamic) links through Thymeleaf.
Now the first url I want to link to is /resource/id so I have the following:
<a th:href="|/resource/${resource.id}|" href="#" class="btn btn-default">Edit...</a>
Which works great, and does exactly what you would expect.
So the next url I want to link to is /resource/id/child/id so I try the following:
<a th:href="|/resource/${resource.id}/child/${child.id}|" href="#" class="btn btn-default">Edit...</a>
Which I thought would give me what I wanted. Instead I get:
/resource/3/child%7D?id=4
Which is weird and confusing. I'm not really sure why this happens or how to get what I want which is:
/resource/3/child/4
Any help greatly appreciated. I'm using spring-boot/spring-mvc if it makes any difference.
Update:
Okay, so after re-reading (and comprehending) the documentation, it turns out the the more correct syntax is:
<a th:href="#{/resource/{rid}/child/{cid}(rid=${resource.id} cid=${child.id})}" href="#" class="btn btn-default">Edit...</a>
Now I get the url:
/resource/3/child?id=4
Which while very close is still slightly wrong and confusing.
Does Thymeleaf not support more than one path variable?

I think a comma is missing. Try like this :
th:href="#{/resource/{rid}/child/{cid}(rid=${resource.id},cid=${child.id})}"
Each key/value should be separate with a comma in order to correctly build an URL with multiple path variables.

When working with urls you should better use the url syntax #{...} instead of literal substitution.
For example in your case:
<a th:href="#{/resource/{resource.id}/child/{child.id}}"
href="#" class="btn btn-default">Edit...</a>
(note the absence of the dollar sign in rest resource placeholders)

Have you check the value of child.id? I used it very often like #{|/resource/${resource.id}/child/${child.id}|}.
You can evaluate the syntax wit
<a th:with="child_id='4'" th:href="#{|/resource/${resource.id}/child/${child_id}|}"
and put a <span th:text="${child.id}"></span> to your html to see what value child.id has.

Related

What's wrong with this xpath statement?

Trying to get the color WHITE out of the line of code.
<a href="javascript:void(0)" class="itemAttr current" title="WHITE" data-
value="WHITE"><img src="https://gloimg.rglcdn.com/rosegal/pdm-product-
pic/Clothing/2019/06/05thumb-img/1559762268621192281.jpg"></a>
I've tried this:
color = driver.find_element_by_xpath("""//p[#id="select-attr-
0"]/a[#href="javascript:void(0)"]#title""").click()
I get this error message:
The string
'//p[#id="select-attr-0"]/a[#href="javascript:void(0)"]#title' is not
a valid XPath expression.
What I want is to get "WHITE".
It looks like you are missing a / before the #title attribute. Try this xpath instead:
//p[#id="select-attr-0"]/a[#href="javascript:void(0)"]/#title
In order to get an attribute value of an element, you need to put '/' before the '#title', so the following should work (provided the parent element p is correctly addressed):
//p[#id="select-attr-0"]/a[#href="javascript:void(0)"]/#title
When working with XPATHs, it is often useful to use one of free online testers to get instant path feedback, e.g. this one
Try using the below xpath snippet.
//p[#id='select-attr- 0']//child::a[#value='WHITE']

How to interpolate ruby language in a link to path

I would like to insert the type of my object in my link to. this one is not always the same so I don't want to write it in real letter.
I would like to write something like :
link to "my mission", edit_+ mission.type.downcase + _path(mission)
I don't even know if its possible.
Thanks for your help
You can use instance_eval like:
link_to "my mission", instance_eval("edit_#{mission.type.downcase}_path(mission)")
You might a regular html tag a little easier:
<a href='<%= edit_+ mission.type.downcase + _path(mission)%>'>
mission_path
</a>

Select either A or B with Or Operator in XPath

I'm trying to crawl some websites, and the data I want can be found either of these places depending on the site:
Page 1:
<div>
<ul>
<li class="asd"> SomeText1 </li>
</ul>
</div>
Page 2:
<div>
<ul>
<li class="dsa"> SomeText2 </li>
</ul>
</div>
I would like an XPath expression which tries to select SomeText1 first, and if it doesn't exist, tries to get SomeText2.
I've tried //li[#class="asd"]/text() or //li[#class="dsa"]/text(), but this doesn't seem to cut it.
Am I using the or operator wrong? If so, how is it supposed to be used?
EDIT
I'm trying to feed a crawler an XPath in order to find information to store in a DB. On a given webpage, can the information I'm trying to get be two different places?
Which means webpage 1 could be:
<AA>
<BB>
<CC> Test </CC>
</BB>
</AA>
and on another there could be
<DD>
<EE>
<FF> Test </FF>
</EE>
</DD>
How can I construct an XPath expression which can say either do
AA/BB/CC or (if it fails/doesn't exist) DD/EE/FF?
You can shorten it to:
//li[#class = 'asd' or #class = 'dsa']/text()
Having said that, "not working" is never an accurate description of what went wrong. A potential source of error is double quotes instead of single quotes. If there are double quotes arround the expression, any quotes inside must be single.
Am I using the or operator wrong ?
No, your usage of the or operator is fine. Something else went wrong. (To really diagnose your problem, we'd need more context).
Try...
//li[#class="asd" or #class="dsa"]/text()

Unable to find Dynamic Xpath

My xpath is :
//*[#id='form_MenuBar:j_id24']/span
and the value # 24 changes.
//*[#id='form_MenuBar:j_id48']/span
I tried but doesn't works.
driver.findElement(By.xpath("//a[contains(#id,'form_MenuBar:j_id$')]/span"));
Source XML:
<li class="ui-menuitem ui-widget ui-corner-all ui-menuitem-active" role="menuitem">
<a id="form_MenuBar:j_id24" class="ui-menuitem-link ui-corner-all ui-state-hover" href="/Demand/j_spring_security_logout">
<span class="ui-menuitem-text">Log off</span>
</a>
</li>
Just try
driver.findElement(By.xpath("//a[contains(#id,'form_MenuBar:j_id')]/span"));
If you are using contains in xpath no need to use '$'.
It appears that you are using java so I'll try to answer it based on that. I'm not a java developer so I apologize if it's not syntactically correct.
If all that is changing is the number within the ID, and you know the ID, you could do:
driver.findElement(By.id(String.format("form_MenuBar:j_id%d", the_id));
Also, I'm not sure about your application that you are testing, but if there are multiple elements that have an id beginning with "form_MenuBar:j_id", then findElement will only find the first one, which might not be the link you are attempting to find.
you could use findElements which will return a list of all elements that match that and then iterate through those until you find the one you really want.

How to match elements after an element with certain content or attribute?

Simplified example
<td>caption</a>
<a id="tt-1">text1</a>
<a id="tt-2">text2</a>
<td>topics</td>
<a id="tt-3">text3</a>
<a id="tt-4">text4</a>
<a id="tt-5">text5</a>
What I need is to match all a elements below <td>topics</td>.
Note that there are plenty of elements between those elements in example. Also <td> may be enclosed into other elements.
My current real-world XPath expression looks like this
//a[contains(#id,'tt-')]
Updated to be closer to real-world
Another update to clarify.
Based on your statement "What I need is to match all a elements below <td>topics</td>"
//td[.='topics']/a
I'm sure that's not the whole story, though.
Based on your updated example:
//a[starts-with(#id, 'tt-') and preceding-sibling::td[1] = 'topics']

Resources