【问题标题】:Conditionally set an attribute on an element with JSP Documents (JSPX)使用 JSP 文档 (JSPX) 有条件地在元素上设置属性
【发布时间】:2010-09-14 11:52:13
【问题描述】:

在 HTML 表单中,可以通过在按钮上定义“禁用”属性来禁用按钮,其值为任意值:

<button name="btn1" disabled="disabled">Hello</button>

如果要启用按钮,则该属性不应存在,因为没有可以将 disabled 属性设置为使按钮保持启用状态的定义值。

当我想在使用 JSP 文档 (jspx) 时启用/禁用按钮时,这会导致我出现问题。由于 JSP 文档必须是格式良好的 XML 文档,我看不到任何有条件地包含此属性的方式,因为以下内容是不合法的:

<button name="btn1" <%= (isDisabled) ? "disabled" : "" %/> >Hello</button>

虽然我可以使用 JSTL if 标记复制标记两次以获得所需的效果,但在我的特定情况下,我在按钮上声明了超过 15 个属性(AJAX 的许多 javascript 事件处理程序属性),因此复制标记正在进行使 JSP 变得非常混乱。

如何在不牺牲 JSP 可读性的情况下解决这个问题?是否有任何自定义标签可以通过操作输出 DOM 向父级添加属性?

【问题讨论】:

    标签: jsp xhtml webforms jspx


    【解决方案1】:

    我并没有真正使用 JSP(我回复过一次,然后在我理解“必须通过有效的 XML”这件事时将其删除)。我能想到的最干净的是:

    <% if (isDisabled) { %>
      <button name="btn1" disabled="disabled">Hello</button>
    <% } else { %>
      <button name="btn1">Hello</button>
    <% } %>
    

    【讨论】:

    • 如问题中所述,虽然这会起作用,但它比我想要的更混乱,尤其是 if 语句的两个分支之间共有 15 个以上的属性。
    【解决方案2】:

    语法不是 JSP 文档所需的合法 XML。你有两个选择:

    1. 替换 with (isDisabled) ? “禁用”:“”
    2. 使用 Core taglib 和 EL(确保将 isDisabled 放入页面范围),如下所示:
    "禁用"""选择>

    希望有帮助:)

    【讨论】:

    • 这些标签会放在哪里呢?您仍然无法将它们放在按钮标记的属性部分中,因为这仍然是无效的 XML,并且将它们放在元素中只会导致添加一些 CDATA。
    【解决方案3】:

    阅读有关自动 jsp to jspx converter 的信息时,我遇到了 &lt;jsp:element&gt;&lt;jsp:attribute&gt; 标签。如果我理解正确,您应该能够执行类似的操作

    <jsp:element name="button">
      <jsp:attribute name="someAttribute">value</jsp:attribute>
    </jsp:element>
    

    并有jsp引擎输出

    <button someAttribute="value"/>
    

    或类似的东西。上面页面中指出的唯一问题是,这似乎不适用于条件构造。转换器的作者解决了创建一些帮助标签的问题,你可以看看下载我猜的源代码。希望对您有所帮助。

    【讨论】:

    • 其实大概就是 之类的。 JSP2X 工具将这些作为自定义标签写入您的 WEB-INF 中,以便在转换后的 JSP 文件中使用。
    【解决方案4】:

    我使用具有动态属性的自定义 JSP 标记。你可以这样使用它:

    <util:element elementName="button" name="btn1" disabled="$(isDisabled ? 'disabled' : '')"/>
    

    基本上,这个标签的作用是生成一个带有 elementName 的 XML 元素,并将所有存在的属性放在标签中,但会跳过空的。

    标签本身很容易实现,我的实现只有 44 行。

    【讨论】:

    • 你能发布代码吗?我认为这会很有启发性。
    • 这似乎是我能得到的最佳答案,可惜没有办法用有效的 XML 语法做到这一点,而不必编写自定义标签......
    • 如果您查看 JSP2X 工具,它会删除 和 (用于元素的主体)的标签。这是另一种可用于更复杂结构的替代方案。
    • 使用三元运算符的绝佳解决方案。记下我的一些例子。
    【解决方案5】:

    您可以使用&lt;jsp:text&gt; 标签通过有效的 XML 解决此问题:

    <jsp:text><![CDATA[<button name="btn1"]]></jsp:text>
        <c:if test="${isDisabled}"> disabled="disabled"</c:if>
        >
        Hello!
    <jsp:text><![CDATA[</button>]]></jsp:text>
    

    这显然比其他一些解决方案更冗长。但它是完全独立的:不需要自定义标签。此外,它可轻松扩展到您需要的任意数量的属性。

    【讨论】:

    • 如果您投反对票,请留言说明原因。这让我有机会改进答案。
    • 对这个答案的反对意见如此之多,但实际上没有人说出原因。 :-(
    • 我不知道为什么有人反对这个答案,但我觉得这是最适合我的方法。
    • 我没有投反对票,但是这种方法使 JSP 本身更难阅读,尤其是如果一遍又一遍地重复并且您丢失了带有适当标签的 XML 验证。
    • @ArchimedesTrajano 你说得对——我已经指出了这种方法的好处和坏处。如果可读性很重要,那么您应该使用自定义标签。整个问题说明了为什么使用 jspx 不是一个好主意!
    【解决方案6】:

    我想自上一篇文章以来已经过去了一段时间,但我遇到了与 &lt;select&gt;&lt;option selected="selected"&gt; 标签完全相同的问题,即动态声明选择了哪个选项。为了解决这个问题,我制作了一个自定义 tagx;我将详细信息发布在另一个answer here

    我得出的结论是,没有好的捷径; EL 和 JSP 表达式只能存在于 XML 元素属性中(以及正文内容中)。因此,您必须执行以下操作;

    <c:choose>
        <c:when test="${isDisabled}"><button name="btn1" disabled="disabled">Hello</button></c:when>
        <c:otherwise><button name="btn1">Hello</button></c:otherwise>
    </c:choose>
    

    使用 scriptlet 表示法不适用于 JSP 文档 (.jspx)

    【讨论】:

    【解决方案7】:

    我一直在努力解决同样的问题。我尝试在&lt;c:if&gt; 中使用&lt;jsp:attribute name="disabled"/&gt;,但编译器尝试将禁用属性附加到失败的c:if 元素。但我发现这确实有效(stripes:submit 是用于创建带状提交类型按钮的元素):

    <stripes:submit name="process" value="Hello">
       <jsp:attribute name="disabled">
           <c:if test="${x == 0}">disabled</disabled>
       </jsp:attribute>
    </stripes:submit>
    

    如果正文只包含空格,jsp:attribute 似乎根本不会创建属性,所以你要么得到disabled="disabled",要么什么都没有。

    这仅在您使用某种标记库生成按钮时才有效,并且标记元素必须支持禁用属性(将其传递给底层 HTML 元素)。您不能使用 jsp:attribute 向原始 HTML 元素添加属性。

    【讨论】:

    • 对我不起作用...即使标签的正文为空,也会创建该属性。我想这取决于您使用的 JSP 的 impl(我使用的是树脂 3.0.24)
    【解决方案8】:

    制作一个标签库(.tagx)然后使用scriptlet标签。

    http://code.google.com/p/jatl/wiki/JSPExample

    <?xml version="1.0" encoding="UTF-8" ?>
    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1">
    <jsp:directive.page import="com.googlecode.jatl.Html"/>
    <jsp:directive.page import="com.evocatus.product.data.AttributeValue"/>
    <jsp:directive.page import="com.evocatus.domain.Product"/>
    
    <jsp:scriptlet>
    //<![CDATA[
        final Product p = (Product) request.getAttribute("product");
            new Html(out) {{
               for (AttributeValue v : p.summaryAttributeValues()) {
                       p();
                            strong().text(v.getLabel()).end();
                            text(": " + v.getValue());
                       endAll();
               }
            }};
    //]]>
    </jsp:scriptlet>
    
    </jsp:root>
    

    是的,这是作弊......但它可以完成工作。另外,您能否以这种方式对树结构进行非常讨厌的复杂递归。

    我还在我的博客和 gist.github 上发布了另一个解决方案,它使用了一堆 tagx 库:http://adamgent.com/post/8083703288/conditionally-set-an-attribute-on-an-element-with-jspx

    【讨论】:

      【解决方案9】:

      @alex 使用三元运算符的绝佳解决方案。我添加了一些我的例子,感谢你,我只是改变了条件的结果,如果为真,则写入属性,否则不写任何东西

      填充列表并选择使用的值,避免使用 c:if

      <select id="selectLang" name="selectLang" >
      <c:forEach var="language" items="${alLanguages}" >
          <option value="${language.id}" ${language.code == usedLanguage ? 'selected' : ''} >${language.description}</option>
      </c:forEach>
      

      在开始时检查单选按钮以避免 c:if:

      <input type="radio" id="id0" value="0" name="radio" ${modelVar == 0 ? 'checked' : ''} />
      <input type="radio" id="id1" value="1" name="radio" ${modelVar == 1 ? 'checked' : ''} />
      <input type="radio" id="id2" value="2" name="radio" ${modelVar == 2 ? 'checked' : ''} />
      

      【讨论】:

      • 可以将language.code == usedLanguage 更改为检查language.code 是否存在于某个列表中吗?我想检查类似:someList.contains(language.code),但它失败了。
      【解决方案10】:

      我像https://stackoverflow.com/a/207882/242042一样实现了它,并封装了https://stackoverflow.com/a/775295/242042,这样它就可以作为标签重复使用了。

      <%@ tag
        display-name="element"
        pageEncoding="utf-8"
        description="similar to jsp:element with the capability of removing attributes that are blank, additional features depending on the key are documented in the tag."
        trimDirectiveWhitespaces="true"
        dynamic-attributes="attrs"
      %>
      <%@ attribute
        name="tag"
        description="Element tag name.  Used in place of `name` which is a common attribute in HTML"
        required="true"
      %>
      <%-- key ends with Key, use i18n --%>
      <%-- key starts with x-bool- and value is true, add the key attribute, no value  --%>
      <%-- key starts with x-nc- for no check and value is empty, add the key attribute, no value  --%>
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
      <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
      <jsp:text><![CDATA[<]]></jsp:text>
      <c:out value="${tag} " />
      <c:forEach var="attr" begin="0" items="${attrs}">
        <c:choose>
          <c:when test='${fn:endsWith(attr.key, "Key")}'>
            ${attr.key}=<fmt:message key="${attr.value}" />
          </c:when>
          <c:when test='${fn:startsWith(attr.key, "x-bool-") && attr.value == "true"}'>
            <c:out value="${fn:substringAfter(attr.key, 'x-bool-')}" />
          </c:when>
          <c:when test='${fn:startsWith(attr.key, "x-bool-") && attr.value != "true"}'>
          </c:when>
          <c:when test='${fn:startsWith(attr.key, "x-nc-")}'>
            <c:out value="${fn:substringAfter(attr.key, 'x-nc-')}" />="<c:out value='${attr.value}' />"
          </c:when>
          <c:when test='${not empty attr.value}'>
            <c:out value="${attr.key}" />="<c:out value='${attr.value}' />"
          </c:when>
        </c:choose>
        <c:out value=" " />
      </c:forEach>
      <jsp:doBody var="bodyText" />
      <c:choose>
        <c:when test="${not empty fn:trim(bodyText)}">
          <jsp:text><![CDATA[>]]></jsp:text>
            ${bodyText}
          <jsp:text><![CDATA[<]]></jsp:text>
            <c:out value="/${tag}" />
          <jsp:text><![CDATA[>]]></jsp:text>
        </c:when>
        <c:otherwise>
          <jsp:text><![CDATA[/>]]></jsp:text>
        </c:otherwise>
      </c:choose>
      

      要使用它,请将其放在 taglib tagdir 中。

      <%@ taglib tagdir="/WEB-INF/tags" prefix="xyz"%>
      ...
      <xyz:element tag="input"
        type="date"
        id="myDate"
        name="myDate"
        x-bool-required="true"
      />
      

      输出将呈现为

      <input 
          name="myDate"
          id="myDate"
          type="date"
          required/>
      

      【讨论】:

        【解决方案11】:

        使用 pure JSP 的正确方法是:

        <jsp:element name="button">
          <jsp:attribute name="name">btn1</jsp:attribute>
          <jsp:attribute name="disabled" omit="${not isDisabled}">disabled</jsp:attribute>
          <jsp:body>Hello</jsp:body>
        </jsp:element>
        

        关键是在&lt;jsp:attribute&gt; 上使用omit 属性 - 如果表达式的计算结果为true,则该属性根本不会被渲染。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-19
          • 1970-01-01
          • 1970-01-01
          • 2017-05-28
          • 2011-04-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多