Evaluar list.contains string en JSTL

89

Necesito ocultar un elemento si ciertos valores están presentes en el JSP

Los valores se almacenan en una lista, así que intenté:

<c:if test="${  mylist.contains( myValue ) }">style='display:none;'</c:if>

Pero no funciona.

¿Cómo puedo evaluar si una lista contiene un valor en JSTL, la lista y los valores son cadenas?

OscarRyz
fuente
17
Tenga en cuenta que la sintaxis dada funciona según lo previsto desde EL 2.2 (que se incluye como parte de Servlet 3.0 / JSP 2.2 que se lanzó en diciembre de 2009).
BalusC

Respuestas:

70

Lamentablemente, creo que JSTL no admite nada más que una iteración a través de todos los elementos para resolver esto. En el pasado, usé el método forEach en la biblioteca de etiquetas principal:

<c:set var="contains" value="false" />
<c:forEach var="item" items="${myList}">
  <c:if test="${item eq myValue}">
    <c:set var="contains" value="true" />
  </c:if>
</c:forEach>

Después de que esto se ejecute, $ {contiene} será igual a "verdadero" si myList contiene myValue.

Kaleb Brasee
fuente
10
funciona bien si la lista es pequeña. Solo tenga en cuenta que hay un costo de rendimiento al hacerlo de esta manera.
Chii
Sí, lo habría si te colocas lo suficiente. Lo he usado para colecciones de 10-20 cosas y no he experimentado ningún problema de rendimiento. Lo que creo que es peor es la cantidad de líneas de JSTL. Aún así, creo que esta es la única forma sin configurar su propio TLD (que no es demasiado difícil y puede valer la pena).
Kaleb Brasee
97

no hay una función incorporada para verificar eso; lo que haría es escribir su propia función tld que toma una lista y un elemento, y llama al método contains () de la lista. p.ej

//in your own WEB-INF/custom-functions.tld file add this
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
        "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib
        xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
        version="2.0"
        >
    <tlib-version>1.0</tlib-version>
    <function>
        <name>contains</name>
        <function-class>com.Yourclass</function-class>
        <function-signature>boolean contains(java.util.List,java.lang.Object)
        </function-signature>
    </function>
</taglib>

Luego cree una clase llamada Yourclass y agregue un método estático llamado contains con la firma anterior. Estoy seguro de que la implementación de ese método se explica por sí misma:

package com; // just to illustrate how to represent the package in the tld
public class Yourclass {
   public static boolean contains(List list, Object o) {
      return list.contains(o);
   }
}

Entonces puedes usarlo en tu jsp:

<%@ taglib uri="/WEB-INF/custom-functions.tld" prefix="fn" %>
<c:if test="${  fn:contains( mylist, myValue ) }">style='display:none;'</c:if>

La etiqueta se puede utilizar desde cualquier JSP del sitio.

editar: más información sobre el archivo tld - más información aquí

Chii
fuente
4
Recomiendo usarlo en Collectionlugar de Listen el taglib; funciona igual pero admite más tipos de colección como Sets
Ralph
28

Otra forma de hacer esto es usando Map (HashMap)pares de clave y valor que representen su objeto.

Map<Long, Object> map = new HashMap<Long, Object>();
map.put(new Long(1), "one");
map.put(new Long(2), "two");

En JSTL

<c:if test="${not empty map[1]}">

Esto debería devolver verdadero si el par existe en el mapa

tamersalama
fuente
2
Esta es mi forma preferida también, configurar hashmaps en el modelo de vista para todo lo que necesito en una vista. Se integran muy bien con la sintaxis EL y son ultrarrápidos al realizar búsquedas.
Boris B.
Solo una cosa más, si la clave existe pero el valor es nulo o está vacío, devolverá falso.
Zai
1
O si el mapa tiene booleanos, test="${isPresentByValue[myValue]}".
Noumenon
15

Necesita utilizar la función fn:contains()o fn:containsIgnoreCase().

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

...

 <c:if test="${not fn:containsIgnoreCase(mylist, 'apple')}">
        <p>Doesn't contain 'apple'</p>
    </c:if>

o

<c:if test="${not fn:contains(mylist, 'Apple')}">
            <p>Contains 'Apple'</p>
        </c:if>

Nota: Esto funcionará asímylist.toString().contains("apple")y si esto no es lo que está buscando, mejor use otro enfoque.

tk_
fuente
2
Este no es el enfoque correcto. Básicamente se comportará como lo mylist.toString().contains("apple")que no es en absoluto lo que esperarías inicialmente.
BalusC
ohh .. sí, esto no es lo que esperaba. De todos modos actualizaré mi respuesta con esta multa.
tk_
2

La siguiente es más una solución alternativa que una respuesta a su pregunta, pero puede ser lo que está buscando. Si puede poner sus valores en un mapa en lugar de una lista, eso resolvería su problema. Simplemente asigne sus valores a un valor no nulo y haga esto <c:if test="${mymap.myValue ne null}">style='display:none;'</c:if>o incluso puede asignar style='display:none;y simplemente generar${mymap.myValue}

svachon
fuente
Supongo que la sintaxis debería ser <c: if test = "$ {mymap [myValue] ne null}"> style = 'display: none;' </ c: if> De lo contrario, la variable "myValue" no se evalúa.
Andreas
2
${fn:contains({1,2,4,8}, 2)}

O

  <c:if test = "${fn:contains(theString, 'test')}">
     <p>Found test string<p>
  </c:if>

  <c:if test = "${fn:contains(theString, 'TEST')}">
     <p>Found TEST string<p>
  </c:if>
Tony Hung
fuente
0

Si está utilizando EL 3.0+ , el mejor enfoque en este caso es como esta otra respuesta se explica en otro tema:

Para Collectionque sea fácil, simplemente use el Colleciton#contains() método en EL.

<h:panelGroup id="p1" rendered="#{bean.panels.contains('p1')}">...</h:panelGroup>
<h:panelGroup id="p2" rendered="#{bean.panels.contains('p2')}">...</h:panelGroup>
<h:panelGroup id="p3" rendered="#{bean.panels.contains('p3')}">...</h:panelGroup>

Para una Object[](matriz), necesitaría un mínimo de EL 3.0 y utilizaría su nueva compatibilidad con Lambda.

<h:panelGroup id="p1" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p1').get()}">...</h:panelGroup>
<h:panelGroup id="p2" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p2').get()}">...</h:panelGroup>
<h:panelGroup id="p3" rendered="#{bean.panels.stream().anyMatch(v -> v == 'p3').get()}">...</h:panelGroup>

Si aún no está en EL 3.0, necesitará crear una función EL personalizada. [...]

Lucas Basquerotto
fuente
-1

Si está usando Spring Framework, puede usar Spring TagLib y SpEL:

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
---
<spring:eval var="containsValue" expression="mylist.contains(myValue)" />
<c:if test="${containsValue}">style='display:none;'</c:if>
xxg
fuente
-1

Encontré esta solución asombrosa.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%
   ArrayList list = new ArrayList();
   list.add("one");
   list.add("two");
   list.add("three");
%>
<c:set var="list" value="<%=list%>" />
<html>
<body>
        My list is ${list}<br/>
<c:if test='${fn:contains(list, "two")}'>
        My list contains two <br/>
</c:if>
<c:if test='${fn:contains(list, ",")}'>
        My list contains , 
</c:if>
</body>
</html>

La salida para el código anterior es

Mi lista es [uno, dos, tres]

Mi lista contiene dos

Mi lista contiene

Espero que esto ayude a alguien.

oOXAam
fuente
-2
<c:if test="${fn:contains(task.subscribers, customer)}">

Esto funciona bien para mi.

Vladislav
fuente
18
Esto está haciendo la verificación después de convertir ambos elementos en una cadena. La lista se convierte en una cadena y no se verifica por elemento. Si task.subscribers es una lista ["uno", "dos", "veintiuno"] será: verdadero para cliente = "uno" (coincidencia dos veces) falso para cliente = "tres" (sin coincidencia) verdadero para cliente = "veinte" (que no es lo que estás buscando)
Ricardo Marimon
2
Siendo consciente de la advertencia de rmarimon, esta respuesta coincidía con mi caso de uso exacto.
CodeReaper