Limit c:forEach to a maximum when using an c:if condition in its body - jstl

I've got a problem with if condition. I'm getting data from DB and everything is viewed on 2 website tables. Tables on website should be limited to 3 rows only. In DB there is a column named 'screen'. 'screen' can be 'first', 'second' or 'both'. 'first' is a first table, 'second' is a second table, 'both' means both tables. For example if I add data as 'first' screen it should be viewed in first table, if I add data as 'both' it should be viewed in both tables etc. I limited it to 3 rows so the problem is if I add 3 'first' screens and 1 'both' screen I see 3 rows on first table but there isn't any row at second screen. That code is for first table:
<c:forEach items="${foo}" var="c" varStatus="status">
<c:if test="${status.count <= 3 && c.screen.equals('both') || status.count <= 3 && c.screen.equals('first')}">
<tr><td>something_bla_bla</td></tr>
</c:if>
</c:forEach>
Code for second table is almost same - diffrence is only c.screen.equals('second')
Adding 3 'first' shows 3 rows - that's OK,
Adding 3 'both' shows 3 rows - that's OK,
But if I add 3 'first' and 1 'both' that 'both' record should be viewed in second table and it isn't because of that 3 limit.

It's just a matter of counting how many rows you have outputted. For example:
<c:set var="count" value="0"/>
<c:forTokens items="first,second,second,both,first,both,second"
delims=","
var="item">
<c:if test="${count lt 3 and 'both,first'.contains(item)}">
<c:out value="${item}"/>
<c:set var="count" value="${count + 1}"/>
</c:if>
</c:forTokens>
<br/>
<c:set var="count" value="0"/>
<c:forTokens items="first,second,second,both,first,both,second"
delims=","
var="item">
<c:if test="${count lt 3 and 'both,second'.contains(item)}">
<c:out value="${item}"/>
<c:set var="count" value="${count + 1}"/>
</c:if>
</c:forTokens>
This will output (ignoring whitespace):
first both first<br/>
second second both
Please note that I'm using 'both,first'.contains(item) which has the same effect as (item eq 'both' or item eq 'first'), but is shorter (especially if you would have move strings to check).

Related

How do you select two different tags via xpath, both at different levels, when one of them is optional

I have a situation where the data is a mix of these format on the same page. In other words, some rows will show up as:
some lengthy XPATH_X uptill here:
<td/>
<td>
I Need this element td
</td>
<td/>
<td/>
<td/>
<td/>
and a few other rows will show in this format:
the same lengthy XPATH_X uptill here:
<td/>
<td>
<span>
I Need this element span
</span>
</td>
<td/>
<td/>
<td/>
<td/>
Please note that there are no differentiating attributes for each of the td tags. I need to select the second row (td) in both the cases.
I'm trying to catch both of the elements using the following xpath:
XPATH_X/*[self::td[position()=2] or self::td[position()=2]/span]
I tried this out on the page but for some reason it doesn't select anything.
Can someone please help me out with this? I've spent more than 2 hours on this already.
You should try XPATH_X/td[2]//text() to retrieve the text whether it's at the root of the td or in a child tag
You can test it here ; in this test I retrieve three results :
the text inside a span inside a td
the text at the root of a td
both the texts at the root of a td and inside the enclosed span (if this doesn't work for you and the text of the td should be retrieved only if there's no span, use XPATH_X/td[position()=2 and not(./span)]/text() | XPATH_X/td[2]/span/text() instead)
To retrieve the elements containing text nodes rather than the text node themselves, you can use the following :
XPATH_X/td[2]//self::node()[text()]

XPath with dittoed fields?

In this document if the second column is blank it means use the previous row's value.
<doc>
<table>
<tr><td>ASU</td><td>CS</td><td>3</td></tr>
<tr><td>ASU</td><td>English</td><td>3</td></tr>
<tr><td>ASU</td><td></td><td>4</td></tr>
<tr><td>ASU</td><td>French</td><td>3</td></tr>
</table>
<table>
<tr><td>CMU</td><td>CS</td><td>4</td></tr>
<tr><td>CMU</td><td>English</td><td>3</td></tr>
<tr><td>CMU</td><td>French</td><td>3</td></tr>
<tr><td>CMU</td><td></td><td>4</td></tr>
</table>
<table>
<tr><td>SDSU</td><td>English</td><td>3</td></tr>
<tr><td>SDSU</td><td></td><td>4</td></tr>
<tr><td>SDSU</td><td></td><td>5</td></tr>
<tr><td>SDSU</td><td>French</td><td>4</td></tr>
</table>
</doc>
I want rows were the second columns are English so these would be the rows:
<tr><td>ASU</td><td>English</td><td>3</td></tr>
<tr><td>ASU</td><td></td><td>4</td></tr>
<tr><td>CMU</td><td>English</td><td>3</td></tr>
<tr><td>SDSU</td><td>English</td><td>3</td></tr>
<tr><td>SDSU</td><td></td><td>4</td></tr>
<tr><td>SDSU</td><td></td><td>5</td></tr>
What would the XPath be for this?
(This is using XPath 1.0, there may be better solutions with more recent XPath versions).
First, you want trs, so that’s straightforward:
/doc/table/tr[...some predicate...]
The rows you want are either:
Those with where the second tr just contains “English”
tr[2] = 'English'
Or those where the second tr is empty...
tr[2] = ''
and, looking at the previous sibling rows which don’t have an empty second tr...
preceding-sibling::tr[td[2] != '']
the first one ([1]) has a second tr that contains “English”
/td[2] = 'English'
So combining all that, a query that gives you the desired rows is:
/doc/table/tr[td[2] = 'English'
or (td[2] = ''
and preceding-sibling::tr[td[2] != ''][1]/td[2] = 'English')]

How can I select element base on string() in Xpath?

I have an XML like that:
<tr class="TREven">
<td class="Col0">
<span>
<b>Diary Compliance:</b>
Number of Daily Reports completed
<br/>
<i>
* Must be
<u>24</u>
or more
</i>
</span>
</td>
<td class="Col1">
<span class="Red">4 - Not eligible</span>
</td>
</tr>
I don't know how to select "4 - Not eligible" base on my input text (Diary Compliance: Number of Daily Reports completed * Must be 24 or more) which is contained by many child nodes of span before.
Could you help me?
Thanks,
This is alse my trouble
I often use this xpath to get element on cell 2 base on element on cell 1 in a row table like him:
//span[contains(text(),'Diary Compliance: Number of Daily Reports completed * Must be 24 or more')]/../..//span[contains(text(),'4 - Not eligible')]
It's ok until I get trouble when element on cell 1 has lot of format node, I can't pass my exactly text to element on cell 1. In my case, I must use exactly text, not contains text.

How do I concatenate a list of values in JSTL into a single JSTL var?

I’m using JBoss 7.1.3.Final and Spring 3.1.1.RELEASE. On my JSP page, how do I get all the ids of an array into a comma separated string? I have tried this:
<c:forEach var="subject" items="${category.subjects}" varStatus="status">
<c:if test="${status.index == 0}">
<c:set var="cateogrySubjects" value="${subject.id}"/>
</c:if>
<c:if test="${status.index > 0}">
<c:set var="categorySubjects" value="${subject.id},${categorySubjects}"/>
</c:if>
</c:forEach>
Unfortunately the last statement printed is always “subj1,subj1” in the array even if the intermediate values are “subj1”, “subj2”, “subj3”, etc. Any help on concatenating things would be great.

How to get the second set of values in li using xpath

<div id="test"><div class="contains"><ul class = "value"><li> 1 </li><li> 2 </li><li> 3 </li></Ul></div></div>
<div id="test"><div class="contains"><ul class = "value"><li> 1 </li><li> 3 </li><li> 6 </li></Ul></div></div>
Please help me...
Here i need to select any value from the second list of li. All the attributes div with ID and class are of same. im unable to select
If you're sure it will always be the second list of li, more acurately the LIs in the UL from the 2nd , you can select these with [2] to select the 2nd div with id=test (by the way, 2 elements should not share IDs...)
./div[#id="test"][2]/div[#class="contains"]/ul[#class="value"]/li

Resources