JSTL how to get dynamic token position - java

I have something like this:
22-04-19 20:34:00!Color::blue!Manufacturer::Ford!Seats::4!Climatronic::yes
I want to get the name of the category and its value (category::value).
The problem is that these positions (category::value) can shift places. ForTokens is index is not good here as it can be one or 10 different tokens.
<c:if test="${fn:contains(dataset, 'Color')}">
<c:set var="color1" value="${fn:substringAfter(dataset, 'Color::')}" />
<c:set var="color2" value="${fn:substringBefore(color1, '!')}" />
</c:if>
Something like this will also not work as it will print out the same value until the new one will appear (will fill out all null cells). I'm out of ideas.

You can split the initial string and loop over each item to find the category you need:
<c:set var="string1" value="22-04-19 20:34:00!Color::blue!Manufacturer::Ford!Seats::4!Climatronic::yes" />
<c:set var="categories" value = "${fn:split(string1, '!')}" />
<c:forEach var="category" items="${categories}" varStatus="status" >
<c:if test="${status.index != 0}">
<c:set var="decodedCategory" value="${fn:split(category,'::')}" />
Category: <c:out value="${decodedCategory[0]}" />
Value: <c:out value="${decodedCategory[1]}" />
<br />
</c:if>
</c:foreach>

Related

How to use spring:message in a forEach loop

I have been working on a system that provides bilingual support to a website from a database using the <spring:message /> tag library.
I can read/write to the applications en/fr properties files. When I hardcode what would be a new key <spring:message /> will display it correctly. Ex) <spring:message code="f12345' /> will display "test data".
What I am having problems doing is using a dynamic key. No matter how I try to attach the key it fails.
Here are the methods I have tried group by end result.
500 error org.apache.jasper.JasperException: (line: [104], column: [29]) [quote/equal] symbol expected
<spring:message var><c:out value="${CLUObject.SpringKey_name()}" /></spring:message>
<spring:message var='<c:out value=\"${CLUObject.SpringKey_name()}\" />" text="wrong" />
<spring:message code="<c:out value="${CLUObject.SpringKey_name()}" />" text="${CLUObject.SpringKey_name()}" />
<spring:message code=<c:out value="${CLUObject.SpringKey_name()}" /> text="${CLUObject.SpringKey_name()}" />
<spring:message code= <c:out value="${CLUObject.SpringKey_name()}" /> />
Next we have the non-server crash which simply causes the table to not display
<spring:message var='<c:out value="application.message" />' arguments="${CLUObject.SpringKey_name()}" />
<spring:message var='<c:out value="${CLUObject.SpringKey_name()}" />' text="wrong" />
<spring:message code="<c:out value=\"${CLUObject.SpringKey_name()}\" />" />
<spring:message code="${CLUObject.SpringKey_name()}" />
<spring:message code="messageCode" arguments="$value1}" />
<c:set var="temp" > <c:out value="${CLUObject.SpringKey_name()}" /> </c:set><td><spring:message code="messageCode" arguments="${temp}" htmlEscape="false" /></td>
The best I have managed to get to simply displays the text of the key instead of the value. Which can already be done using <spring:message text="${CLUObject.SpringKey_name()}" />'
In the applicationResources file
messageCode=Test message for {0}.
Then inside the jsp page
<c:set var="temp" > <c:out value="${CLUObject.SpringKey_name()}" /> </c:set>
displays "Test message for CLUVALUE.C1111."
I found one site online which appeared to be doing the same thing.
<form:select path="${path}">
<c:forEach var="i" items="${items}">
<form:option value="${i[itemValue]}">
<c:choose>
<c:when test="${localize}">
<spring:message code="${i[itemLabel]}" text="${i[itemLabel]}"/>
</c:when>
<c:otherwise>
<c:out value="${i[itemLabel]}"/>
</c:otherwise>
</c:choose>
</form:option>
I have found a second example where they have a dynamic key with the spring message being used in a forEach loop. Search for spring:message and its 14/17.
<c:forEach items="${errors.allErrors}" var="error">
<spring:message code="${error.code}" text="${error.code}"/><br/>
</c:forEach>
I have found a third example.
In the three examples I have found, the spring:message are all used the same, with the code and text attributes being the same.
I cant see the output, and I cant be sure that their text argument isnt being displayed instead.
Here is the controller block
List<CLU_STRUT> myCLUs = cluService.BuildCLUs();
model.addAttribute("CommonLookUp", myCLUs);
And here is the JSP
<c:forEach var="CLUObject" items="${CommonLookUp}" varStatus="vs">
<tr>
<c:set var="temp" > <c:out value="${CLUObject.SpringKey_name()}" /> </c:set>
<td><spring:message code="messageCode" arguments="${temp}" htmlEscape="false" /></td>
<td><c:if test="${CLUObject.getCountNew() gt 0}"> <a href='drillview?drillvalue=${CLUObject.SpringKey_name()}&mode=drill&drilltype=I'><c:out value="${CLUObject.getCountNew()}" /></a></c:if><c:if test="${CLUObject.getCountNew() eq 0}">0</c:if></td>
<td><c:if test="${CLUObject.getCountMod() gt 0}"> <a href='drillview?drillvalue=${CLUObject.SpringKey_name()}&mode=drill&drilltype=U'><c:out value="${CLUObject.getCountMod()}" /></a></c:if><c:if test="${CLUObject.getCountMod() eq 0}">0</c:if></td>
<td><c:if test="${CLUObject.getCountDelete() gt 0}"> <a href='drillview?drillvalue=${CLUObject.SpringKey_name()}&mode=drill&drilltype=D'><c:out value="${CLUObject.getCountDelete()}" /></a></c:if><c:if test="${CLUObject.getCountDelete() eq 0}">0</c:if></td>
<td><c:out value="${CLUObject.getCountTotal()}" /></td>
</tr>
</c:forEach>
TLDR; How to use spring:message where the key is dynamic in a jsp page.
I finally figured out what the issue was.
Short Answer: the inversion of control was causing things to happen now how I expected. I was trying to access a function or member, and it kept trying to use a get version of it. Since I did not have specifically getmember() to access the variable, it was doing strange and wrong things.
By introducing public String getspring_name() {return spring_name;} all of a sudden the <spring:message code="${CLUObject.spring_name}" /> works.
Long Answer: In another section of my code I discovered what I thought was a private string member being accessed in a jsp page. After considerable testing of other private variable types and functions, my original thought that I was gaining access to the private member was disproved. Yet, this specific one was being accessed. After more testing I discovered when I had a get function in a very specific naming convention this behavior was reproducible. So in this case I had a private String CLU_Name, and was lucky enough to have created the get function as getCLU_Name(). Having named other get functions like getCountDelete() for Count_Delete was not allowing me to reproduce the behavior for THEM, because they did not fit the naming pattern.

JSP if statement - String to number

I am new to this so be gentle. I am working on a JSP page and would like implement an if statement.
command.total is set previously and I can't change its type.
<c:set var="number1" value="${5}"/>
<c:set var="number2" value="${0}"/>
<c:set var="number3" value="${command.total}"/>
<c:out value="${number1}" />
<c:out value="${command.total}" />
<c:choose>
<c:when test="${number1 < number2}">
${"number1 is less than number2"}
</c:when>
<c:when test="${number1 > number3}">
${"aaaaaaaaaaaaaaaaaaaa"}
</c:when>
<c:otherwise>
${"cccccccccccccccccccccccccccccccccc"}
</c:otherwise>
</c:choose>
This always fails and I believe that the problem is that command.total is returned as a string.
I have tried to convert the string with the following:
<fmt:parseNumber value="command.total" var="test" integerOnly="TRUE" type="NUMBER"></fmt:parseNumber>
<c:out value="${test}"></c:out>
Is it possible to convert this string to a number?

Manipulating Hashtable key is not working

I am trying to access a Hashtables value based on its key, which is a number as String in JSTL.
But if I increment/decrement the keys value, it does not work anymore.
I iterate the sorted list of keys in a for loop. I use this item to access Hashtable.
<c:forEach items="${helper:getSortedList(hashtableObj)}" var="lineNumber" varStatus="loop">
<c:if test="${param.lineNbr eq lineNumber}">
<c:if test="${lineNumber>1}">
<fmt:parseNumber var="prevLineNumberKey" type="number" value="${lineNumber-1}" />
<c:out value="PREV ${hashtableObj[prevLineNumberKey]}" escapeXml="false"/><br/>
</c:if>
<c:out value="Current :${lineNumber}" /><br/>
<c:if test="${lineNumber<fn:length(hashtableObj)-1}">
<fmt:parseNumber var="nextLineNumberKey" type="number" value="${lineNumber+1}" />
<c:out value="NEXT ${hashtableObj[nextLineNumberKey+1]}" escapeXml="false"/><br/>
</c:if>
</c:if>
</c:forEach>
The output is
PREV Current :51 NEXT
But what I expected is
PREV 50 Current :51 NEXT 52
Any pointers are appreciated.
If keys in your Map is String than to get an element you must query it with String value. Your current solution queries a Map with Long value.
You can convert number to String and then query a Map like this:
<c:set var="numberAsString">${50 - 1}</c:set>
<c:out value="value: ${hashtableObj[numberAsString]}"/>
Try replacing:
<fmt:parseNumber var="prevLineNumberKey" type="number" value="${lineNumber-1}" />
With:
<c:set var="prevLineNumberKey">${lineNumber-1}</c:set>
And replace:
<fmt:parseNumber var="nextLineNumberKey" type="number" value="${lineNumber+1}" />
<c:out value="NEXT ${hashtableObj[nextLineNumberKey+1]}" escapeXml="false"/><br/>
With:
<c:set var="nextLineNumberKey">${lineNumber+1}</c:set>
<c:out value="NEXT ${hashtableObj[nextLineNumberKey]}" escapeXml="false"/><br/>
Couple of questions though:
1) Is hashtableObj really a hashtable or is it a hashmap?
2) Is the value of the hashtableObj, really a number that is equal to the key? In other words you are expecting:
PREV 50
... that means you are expecting the value of the hashtable/map to be 50 AND the key is also 50?
I found a workaround.
<fmt:parseNumber var="prevLineNumberKey" type="number" value="${lineNumber-1}" />
<c:out value="Previous ${hashtableObj[sortedList[prevLineNumberKey-1]]}" escapeXml="false"/><br/>
I used the list element as a key for Hashtable and it works. Thanks to all answers.

Increment counter with loop

This question is related to my previous question :
Jsp iterate trough object list
I want to insert counter that starts from 0 in my for loop, I've tried several combinations so far :
1.
<c:forEach var="tableEntity" items='${requestScope.tables}'>
<c:forEach var="rowEntity" items='${tableEntity.rows}' varStatus="count">
<c:out value="${count}" />
</c:forEach>
</c:forEach>
2.
<c:set var="count" value="0" scope="page" />
<c:forEach var="tableEntity" items='${requestScope.tables}'>
<c:forEach var="rowEntity" items='${tableEntity.rows}'>
<%=count++%>
<c:out value="${count}" />
</c:forEach>
</c:forEach>
Problem with first approach is that outer loop has 3 items and inner loop has 7 items, so for each outer item the count starts from 0. The second one I get compile error. Here is basically what I want :
counter = 0;
outer for loop
inner for loop
counter++;
//cout/echo/print counter value should start from 0
end inner loop
end outer loop
I'm just not totally familiar with the syntax. thank you
Try the following:
<c:set var="count" value="0" scope="page" />
//in your loops
<c:set var="count" value="${count + 1}" scope="page"/>
The varStatus references to LoopTagStatus which has a getIndex() method.
So:
<c:forEach var="tableEntity" items='${requestScope.tables}' varStatus="outer">
<c:forEach var="rowEntity" items='${tableEntity.rows}' varStatus="inner">
<c:out value="${(outer.index * fn:length(tableEntity.rows)) + inner.index}" />
</c:forEach>
</c:forEach>
See also:
Hidden features of JSP/Servlet
You can use varStatus in your c:forEach loop
In your first example you can get the counter to work properly as follows...
<c:forEach var="tableEntity" items='${requestScope.tables}'>
<c:forEach var="rowEntity" items='${tableEntity.rows}' varStatus="count">
my count is ${count.count}
</c:forEach>
</c:forEach>
what led me to this page is that I set within a page then the inside of an included page I did the increment
and here is the problem
so to solve such a problem, simply use scope="request" when you declare the variable or the increment
//when you set the variale add scope="request"
<c:set var="nFilters" value="${0}" scope="request"/>
//the increment, it can be happened inside an included page
<c:set var="nFilters" value="${nFilters + 1}" scope="request" />
hope this saves your time

Assigning outcome of another JSTL tag as value of one JSTL tag

I've got this, which is working:
<c:choose>
<c:when test="${sometest}">
Hello, world!
</c:when>
<c:otherwise>
<fmt:message key="${page.title}" />
</c:otherwise>
</c:choose>
And I want to change it to this:
<c:choose>
<c:when test="${sometest}">
<c:set var="somevar" scope="page" value="Hello, world!"/>
</c:when>
<c:otherwise>
<c:set var="somevar" scope="page" value="<fmt:message key="${page.title}">"
</c:otherwise>
</c:choose
But of course the following line ain't correct:
<c:set var="somevar" scope="page" value="<fmt:message key="${page.title}">"
How can I assign to the somevar variable the string resulting from a call to fmt:message?
The fmt:message has a var attribute as well which does effectively what you want.
<fmt:message key="${page.title}" var="somevar" />
That's all. Bookmark the JSTL tlddoc, it may come in handy.
It is also possible to specify the value to set using the contents of the body, rather than through the value attribute:
<c:set var="somevar" scope="page">
<fmt:message key="${page.title}"/>
</c:set>
You'll have to do with:
<c:set var="title"><fmt:message key="${page.title}"></c:set>
<c:set var="somevar" scope="page" value="${title}" />
Since you can't use <fmt:message .. /> on that spot is my experience, has to do with nesting like you suggested. Or go with #balusc suggestion ;-)

Categories