XSLT <xsl:element> equivalent in JSP? - java

When writing XML-compliant JSP, it is difficult to generate different HTML tags according to the input (e.g. when outputting the different tags in a <table>).
The standard solution is to use if or choose tags, but sharing code inside the HTML tag becomes a problem. E.g.
<c:choose>
<c:when test="${i.tag = 'th'}><th> <!-- 100 lines of code --> </th></c:when>
<c:when test="${i.tag = 'td'}><td> <!-- 100 lines of code duplicated?! --> </td></c:when>
</c:choose>
XSLT offers an <xsl:element> tag which allows you to build a tag and its attributes with standard XML syntax. Is there such a tag in any tag library in JSP?

Shouldn't you be doing this like?
<c:choose>
<c:when test="${i.tag = 'th'}"><th></c:when>
<c:when test="${i.tag = 'td'}"><td></c:when>
</c:choose>
<!-- 100 lines of code -->
<c:choose>
<c:when test="${i.tag = 'th'}"></th></c:when>
<c:when test="${i.tag = 'td'}"></td></c:when>
</c:choose>
If you want your markup to be valid XML; make use of a custom tag that wraps all the Java code you want to avoid duplicating. Your markup would then look something like
<c:choose>
<c:when test="${i.tag = 'th'}">
<th>
<my:customTag anyAttributes="th-related-values-if-any" ... />
</th>
</c:when>
<c:when test="${i.tag = 'td'}">
<td>
<my:customTag anyAttributes="td-related-values-if-any" ... />
</td>
</c:when>
</c:choose>
Alternatively, the following hack (suggested by #Uooo) can be used to pass XML validators.
<c:choose>
<c:when test="${i.tag = 'th'}"><c:out value="<th&gt%" /></c:when>
<c:when test="${i.tag = 'td'}"><c:out value="<td&gt%" /></c:when>
</c:choose>
<!-- 100 lines of code -->
<c:choose>
<c:when test="${i.tag = 'th'}"><c:out value="</th&gt%" /></c:when>
<c:when test="${i.tag = 'td'}"><c:out value="</td&gt%" /></c:when>
</c:choose>

You could create a seperate JSP containing your "100 lines of code" and include it.
Replace your <!-- 100 lines of code --> with:
<jsp:include page="hundredLines.jsp">
<jsp:param name="beanParam" value="beanValue"/>
</jsp:include>
And in your hundredLines.jsp:
Bean can be used like ${beanParam}

No. JSP requires knowing the tags when it builds its trees. That makes the operation of JSP more robust
However, you can address the duplicated code by factoring it into a separate JSP file and including it, depending on the implementation of JSP you are using.
Alternatively, you can create a JSP tag that holds the 100 lines of code. It is probably not worth while to do this.
Finally, you could, instead of using th and td, use styles on td to make td look like th. That would make the element look like
<td style="${i.tag == 'th' ? '' : 'font-style: bold; text-align: center;'}">
100 lines of code
</td>
I know I don't have the style quite right, but you could use styleClass instead and play with it in your CSS.

Related

How to compare two variables in jsp

I am using the following code to compare two variables, but it seems it has an error as the page does not get loaded at all.
Based on this answer my code should be correct but surprisingly does not work.
If I remove the <c:when> line it shows
the values of ${name} and ${myvar.employee.name}.
<c:forEach var="myvar" items="${user.names}">
${name}
${myvar.employee.name}
<c:when test="${name eq myvar.employee.name}">
hello
</c:when>
The structure with <c:when> requires <c:choose>
<c:choose>
<c:when test="${your condition here}">
</c:when>
<c:otherwise>
</c:otherwise>
</c:choose>
otherwise you will get error.
As Alex has pointed out, you cannot have non-wrapped <c:when> in your code.
But it looks like, in your case, <c:choose> is not required, because you have only a single clause. In this case <c:if> may be a better option:
<c:if test="${name eq myvar.employee.name}">
hello
</c:if>

JSTL NumberFormatException

I have a spring+hibernate application where I make a native query in my DAO layer. The query looks like the following
select name, amount from myTable where id=:id
It is clear that the selected fields are of different data types (String, Number).
In the JSP I want to print the returned result in table so I am using foreach loop to go through each record in the returned set.
I want to put the negative numbers between braces so I am using the following code
<c:forEach var="item" items="${resultSet}">
<tr>
<c:forEach var="v" items="${item}" varStatus="st">
<td>
<c:choose>
<c:when test="${v != null}">
<c:choose>
<c:when test="${v<0}">
<c:out value="(${v})"></c:out>
</c:when>
<c:otherwise>
<c:out value="${v}"></c:out>
</c:otherwise>
</c:choose>
</c:when>
<c:otherwise>
<c:out value="-"></c:out>
</c:otherwise>
</c:choose>
</td>
</c:forEach>
</tr>
</c:forEach>
As the first item in the query is string, this code fires NumberFormateException.
I know two solutions for this problem. The first is put the braces in the SQL query but I can not use this solution as the application contains many queries and it will take a lot of time modifying all the queries.
The second solution is to use resultTransformer and convert the returned data into one Object but this is not suitable for the same previous reason.
Is there any workaround to solve this problem ?
Have you tried like this ??
<c:when test=${v<0}>
<c:out value="(${v})"></c:out>
</c:when>
<c:otherwise>
<c:out value="${v}"></c:out>

How to register a renderer for a class in JSP/JSTL?

I was wondering if there is a way to register default renderer for a particular class in JSP/JSTL.
I am on my page displaying a tabular report where each table row arrives as generic List<Object>. Since I don't know the type of particular item in advance I am outputting the value with <c:out ...>. This does toString() as far as I know.
Now I want to change the format based on the class of the item e.g. change the format of decimal numbers. Of course I can't use <fmt:formatXXX ...> because I don't know the type in advance.
I believe this is possible in JSF. But is there a way how to achieve this in JSP?
My best shot sofar would be to convert the List<Object> to List<String> and applying the formatting in my controller class but this is slightly less elegant than register a renederer IMHO.
JSP has no notion of "renderers", it's not a component based MVC framework. But you could create a custom tag for this.
Alternatively, you can do something like this with plain JSTL, it's possible to figure the class of an EL object by just checking Object#getClass():
<c:choose>
<c:when test="${item['class'].name == 'java.lang.Integer'}">
<fmt:formatNumber value="${item}" type="number" />
</c:when>
<c:when test="${item['class'].name == 'java.math.BigDecimal'}">
<fmt:formatNumber value="${item}" type="currency" />
</c:when>
<c:when test="${item['class'].name == 'java.util.Date'}">
<fmt:formatDate value="${item}" type="date" />
</c:when>
<c:otherwise>
<c:out value="${item}" />
</c:otherwise>
</c:choose>

Storing JSP Tags in a Database

I have a requirement to store jsp content in a oracle database. I retrieve it from the database and store it in a string and output it by setting escapeXML to false which renders the html.
<c:out value="${myProfileForm.skinElement.footerContent}" escapeXml="false"/>
This works fine except for tags which end up resolving as html and not tags for example:
<c:choose>
<c:when test="${displayLinks=='true'}">
<jsp:include page="header-myprofile.jsp" />
</c:when>
<c:when test="${displayLinks=='false'}">
<jsp:include page="header-no-menu.jsp" />
</c:when>
<c:otherwise>
<jsp:include page="header-myprofile.jsp" />
</c:otherwise>
</c:choose>
Is there a way to store jsp tags in a database?
Instead of storing JSP in database you can achieve the same thing by using a Templating Engine like Velocity or FreeMarker.

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