You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JSTL如何提取位置动态变化的category::value格式token值

问题背景

待处理原始字符串格式如下,开头为时间戳,后续通过!分隔不定数量的分类名::值格式键值对,键值对的排列位置、总数量均不固定,最少1个最多可达10个:

22-04-19 20:34:00!Color::blue!Manufacturer::Ford!Seats::4!Climatronic::yes

原有实现通过fn:contains判断键名存在后,两次截断字符串取值,存在明显缺陷:目标键不存在时不会重置变量,会复用之前已赋值的变量值填充空单元格,同时基于索引遍历的c:forTokens方案无法适配键值对数量浮动的场景。原有问题代码如下:

<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>
实现方案

方案1:双层分割+Map存储(推荐,无依赖适配任意数量键值对)

核心逻辑是先按!拆分全字符串,跳过第一个时间片段后,对每个属性片段按::拆分出键和值,存入独立Map结构,后续直接按键取值即可,完全避免旧值污染。

<%-- 每次处理前初始化空Map,从根源避免旧值残留 --%>
<c:set var="attrMap" value="${{} }" />

<%-- 第一层分割:按!拆分所有片段 --%>
<c:forTokens items="${dataset}" delims="!" var="segment" varStatus="segStatus">
    <%-- 跳过第一个片段,也就是开头的时间戳 --%>
    <c:if test="${not segStatus.first}">
        <%-- 第二层分割:对属性片段按::拆分键和值 --%>
        <c:forTokens items="${segment}" delims="::" var="part" varStatus="partStatus">
            <c:choose>
                <c:when test="${partStatus.index == 0}">
                    <c:set var="currentKey" value="${part}" />
                </c:when>
                <c:when test="${partStatus.index == 1}">
                    <c:set target="${attrMap}" property="${currentKey}" value="${part}" />
                </c:when>
            </c:choose>
        </c:forTokens>
    </c:if>
</c:forTokens>

<%-- 后续取值直接从Map获取即可,不存在的键返回null,不会串值 --%>
<tr>
    <td>颜色:${attrMap.Color}</td>
    <td>厂商:${attrMap.Manufacturer}</td>
    <td>座位数:${attrMap.Seats}</td>
    <td>自动空调:${attrMap.Climatronic}</td>
</tr>

该方案优势:

  • 不需要提前预知键值对数量,也不依赖键值对的固定排列顺序
  • 所有键值对一次性解析完成,后续取值不需要重复做字符串截断
  • 完全基于JSTL核心标签和标准EL表达式实现,不需要引入第三方标签库

方案2:取值前重置变量(轻量场景适配)

如果不想引入Map存储全量键值对,可以在每个键的取值逻辑前,先把对应变量手动重置为null,再做存在性判断和截断,即可解决旧值复用的问题。注意判断键存在时要把::后缀带上,避免键名部分匹配导致的误判(比如存在OuterColor键时,仅判断Color会出现误匹配)。

<%-- 取颜色值,先重置变量 --%>
<c:set var="colorVal" value="${null}" />
<c:if test="${fn:contains(dataset, 'Color::')}">
    <c:set var="colorVal" value="${fn:substringBefore(fn:substringAfter(dataset, 'Color::'), '!')}" />
</c:if>

<%-- 取厂商值,先重置变量 --%>
<c:set var="manufacturerVal" value="${null}" />
<c:if test="${fn:contains(dataset, 'Manufacturer::')}">
    <c:set var="manufacturerVal" value="${fn:substringBefore(fn:substringAfter(dataset, 'Manufacturer::'), '!')}" />
</c:if>

<%-- 其余键按相同逻辑实现即可 --%>

内容的提问来源于stack exchange,提问作者Serpher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 03:45:39