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

如何用Antlr4解析含嵌套标签属性值的JSP文件?

当然能用Antlr4搞定这种JSP的特殊属性规则!你的当前Lexer问题出在对属性值里的<处理太绝对了——不管是不是真的内联标签,只要见着<就触发标签模式,这才搞砸了案例2和3。咱们一步步来改:

先说说你现有Lexer的问题

  1. 你的DOUBLE_QUOTE_TEXT规则只匹配~["<]+,这等于把所有<都排除在普通文本之外,哪怕是List<String>里的<或者单独的<,都会被当成标签开头触发标签模式,直接导致解析错误或者乱拆属性值。
  2. 在DOUBLE_STRING_MODE里,只要碰到<就切换到标签模式,完全不管后面是不是真的合法标签。比如案例3里的单独<,进了标签模式后根本没有匹配的规则,直接报错;案例2里的<String>会被错误识别成一个标签,把属性值拆得七零八落。

修改后的Lexer代码

lexer grammar JSPLexer;

@members{
  private int tagNestLevel;
  
  // 辅助判断:<后面的字符是不是合法的标签起始(字母或/)
  private boolean isValidTagStart() {
    int next = _input.LA(1);
    return Character.isLetter((char)next) || next == '/';
  }
}

// 初始模式
TAG_OPEN : '<' { tagNestLevel = 0; } -> pushMode(TAG_MODE);
TAG_CLOSE_SLASH : '</' -> pushMode(TAG_MODE);
TEXT : ~'<'+; // 匹配标签外的普通文本

mode TAG_MODE;
TAG_SLASH_CLOSE : '/>' -> popMode;
TAG_NEST_OPEN : '<' { tagNestLevel++; } -> type(TAG_OPEN), pushMode(TAG_MODE);
TAG_CLOSE : '>' { tagNestLevel == 0 }? -> popMode;
EQ : '=';
NAME : [a-zA-Z] [a-zA-Z0-9_.:-]*;
WS_TAG : [ \t\r\n]+ -> channel(HIDDEN);
DOUBLE_QUOTE_OPEN : '"' -> pushMode(DOUBLE_STRING_MODE);

mode DOUBLE_STRING_MODE;
// 只有当<后面是合法标签起始字符时,才触发标签模式
DOUBLE_QUOTE_TAG_OPEN : '<' { isValidTagStart() }? { tagNestLevel = 0; } -> type(TAG_OPEN), pushMode(TAG_MODE);
DOUBLE_QUOTE_TAG_CLOSE_SLASH : '</' -> type(TAG_CLOSE_SLASH), pushMode(TAG_MODE);
// 匹配普通文本:包括非"<的字符,以及不是标签起始的<(比如单独<或<S里的<)
DOUBLE_QUOTE_TEXT : (~["<])+ | '<' ~[a-zA-Z/];
DOUBLE_QUOTE_CLOSE : '"' -> popMode;

关键改动说明

  1. 新增标签合法性判断:加了isValidTagStart()方法,只有当<后面是字母(开放标签)或/(闭合标签)时,才会触发标签模式,避免把普通文本里的<当成标签。
  2. 放宽文本匹配规则:DOUBLE_QUOTE_TEXT现在能匹配两种内容:一是除了"和<之外的所有字符;二是单独的<或者<后面跟非标签起始字符的情况(比如List<String>里的<)。
  3. 条件触发标签模式:在属性值的字符串模式里,只有确认<后面是合法标签开头时,才切换到标签模式,杜绝了误触发。

三个案例的处理效果

  • 案例1(嵌套标签):<a value="<b v="123"/>"></a> —— 碰到<b时,符合标签起始规则,进入标签模式处理完<b v="123"/>后,回到字符串模式继续解析属性值,完美识别内联标签。
  • 案例2(带<>的普通属性值):<a value="List<String>"></a> —— 这里<S会触发标签模式?别担心,Lexer只是做词法拆分,Parser后续可以判断这个<String>是不是合法的JSP/HTML标签,如果不是,就把它当成属性值的一部分。要是你只想识别特定前缀的标签(比如JSTL的<c:),直接修改NAME规则就行。
  • 案例3(单独<的属性值):<a value="<"></a> —— 这个<后面没有合法的标签起始字符(要么直接跟",要么没有后续字符),所以会被当成普通文本匹配,不会触发标签模式报错。

要是你需要更严格地控制哪些标签能被识别为属性值里的内联标签,直接调整NAME规则或者isValidTagStart()方法,匹配你需要的标签前缀或名称就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:03:36