评估list.contains包含JSTL中的字符串


88

如果JSP中存在某些值,则需要隐藏一个元素

这些值存储在一个列表中,所以我尝试了:

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

但是,它不起作用。

如何评估列表是否包含JSTL中的值,列表和值是字符串。


17
注意,给定的语法自EL 2.2(它作为Servlet 3.0 / JSP 2.2的一部分(于2009年12月发布)的一部分)以来就一直在工作。
BalusC 2012年

Answers:


69

可悲的是,我认为JSTL除了支持所有元素的迭代来解决这个问题之外,不支持任何其他功能。过去,我在核心标签库中使用过forEach方法:

<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>

运行之后,如果myList包含myValue,则$ {contains}将等于“ true”。


10
如果列表很小,效果很好。只需意识到以这种方式执行会损失性能。
CHII

是的,如果您的身高够高的话。我已将其用于收集10到20件事,并且没有遇到任何性能问题。我认为更糟糕的是JSTL的行数。不过,我认为这是不设置自己的TLD的唯一方法(这不太困难,可能很值得)。
Kaleb Brasee

97

没有内置功能可以检查-您要做的是编写自己的tld函数,该函数接受一个列表和一个项目,然后调用列表的contains()方法。例如

//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>

然后创建一个名为Yourclass的类,并添加一个带有上述签名的名为contains的静态方法。我确信该方法的实现很容易说明:

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);
   }
}

然后可以在jsp中使用它:

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

可以从站点中的任何JSP使用该标记。

编辑:有关tld文件的更多信息- 更多信息-此处有更多信息


4
我建议使用Collection而不是List在taglib中使用-它的工作原理相同,但支持更多的集合类型,如Sets
Ralph

28

另一种方法是使用Map (HashMap)with和Key,Value对表示您的对象。

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

在JSTL中

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

如果该对在地图中存在,则应返回true


2
这也是我的首选方式,在视图模型中为在视图中需要的所有内容设置哈希图。它们与EL语法很好地集成在一起,并且在搜索时非常快。
鲍里斯·B

再说一件事,如果键存在但值是null或空,则它将返回false。
2014年

1
或者,如果Map包含布尔值,则test="${isPresentByValue[myValue]}"
Noumenon'2

14

您需要使用fn:contains()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>

要么

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

注意: 这将像mylist.toString().contains("apple")其他方法一样工作,如果这不是您想要的,请使用其他方法。


2
这不是正确的方法。它基本上会表现得与mylist.toString().contains("apple")您最初期望的绝对不一样。
BalusC

哦..是的,这不是我期望的。无论如何,我将通过这种改进来更新我的答案。
tk_

2

以下内容更多的是解决方法,而不是问题的答案,但它可能正是您想要的。如果您可以将值放在地图中而不是列表中,那将解决您的问题。只需将您的值映射到非null值,然后执行此操作,<c:if test="${mymap.myValue ne null}">style='display:none;'</c:if>或者甚至可以映射到style='display:none;并简单地输出${mymap.myValue}


我猜语法应该是<c:if test =“ $ {mymap [myValue] ne null}”> style ='display:none;'</ c:if>否则,不会评估变量“ myValue”。
安德烈亚斯(Andreas)2010年

2
${fn:contains({1,2,4,8}, 2)}

要么

  <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>

0

如果您使用的是EL 3.0+,则这种情况下的最佳方法是另一个主题中介绍的其他答案

为了Collection简单起见,只需使用Colleciton#contains() 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>

对于Object[](阵列),您至少需要EL 3.0并利用其新的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>

如果尚未使用EL 3.0,则需要创建一个自定义EL函数。[...]


-1

如果您使用的是Spring Framework,则可以使用Spring TagLib和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>

-1

我发现此解决方案令人惊奇。

<%@ 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>

上面代码的输出是

我的名单是[1、2、3]

我的清单包含两个

我的清单包含,

希望对您有所帮助。


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

这对我来说很好。


18
将两个元素都转换为字符串后,将执行检查。该列表将转换为字符串,并且不会按每个元素进行检查。如果task.subscribers是列表[“一个”,“两个”,“ twentyone”],则将是:对于客户= true =“一个”(匹配两次)对客户= false =“三个”(不匹配)对客户= true “二十”(这不是您正在寻找的内容)
Ricardo Marimon

2
知道rmarimon的警告后,此答案与我的确切用例相符。
2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.