问题描述
Jsonpath-ng 提供基本的算术,如:
from jsonpath_ng import jsonpath
from jsonpath_ng.ext import parse
jsonpath_expr = parse('$.foo * 2')
target = {'foo': 2}
result = jsonpath_expr.find(target)
result = [match.value for match in result]
print(result)
结果:[4]
但是,如果我将表达式更改为 $.foo / 2
,则会出现解析错误:
Traceback (most recent call last):
File "test.py",line 4,in <module>
jsonpath_expr = parse('$.foo / 2')
File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\ext\parser.py",line 172,in parse
return ExtentedJsonPathParser(debug=debug).parse(path)
File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\parser.py",line 32,in parse
return self.parse_token_stream(lexer.tokenize(string))
File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\parser.py",line 55,in parse_token_stream
return new_parser.parse(lexer = IteratorToTokenStream(token_iterator))
File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\ply\yacc.py",line 333,in parse
return self.parSEOpt_notrack(input,lexer,debug,tracking,tokenfunc)
File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\ply\yacc.py",line 1201,in parSEOpt_notrack
tok = call_errorfunc(self.errorfunc,errtoken,self)
File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\ply\yacc.py",line 192,in call_errorfunc
r = errorfunc(token)
File "C:\Users\micha\AppData\Roaming\Python\python38\site-packages\jsonpath_ng\parser.py",line 69,in p_error
raise Exception('Parse error at %s:%s near token %s (%s)' % (t.lineno,t.col,t.value,t.type))
Exception: Parse error at 1:6 near token / (SORT_DIRECTION)
有时我可以通过除以倒数来解决这个问题,所以我会执行 $.foo * 0.5
来获得结果 [1.0]
。但是,如果等式的两边都是不同类型(int 或 float)的数值,这将不起作用。所以 2 * 0.5
和 0.5 * 2
会导致解析错误,但 2.0 * 0.5
不会。
如何让部门工作?为什么我不能将浮点数乘以整数?
解决方法
那些都是语法错误。
-
允许扩展的 JSON 路径以包含“排序”列表的方括号表达式为后缀;每种排序都以
/
或\
开头。为了完成这项工作,扩展词法分析器将这两个符号识别为标记SORT_DIRECTION
,它优先于将/
识别为算术运算符。因此,解析器不允许使用/
作为算术运算符。 (事实上,问题比这更深,但这就是本质。) -
出于某种原因,语法作者选择在算术表达式中将
NUMBER
(实际上是整数)和FLOAT
分开,这意味着他们必须枚举可能的组合。他们选择的是:jsonpath : NUMBER operator NUMBER | FLOAT operator FLOAT | ID operator ID | NUMBER operator jsonpath | FLOAT operator jsonpath | jsonpath operator NUMBER | jsonpath operator FLOAT | jsonpath operator jsonpath
这个语法还有其他问题,但这里的本质是它允许
NUMBER operator NUMBER
和FLOAT operator FLOAT
但不允许NUMBER operator FLOAT
或FLOAT operator NUMBER
,这就是你观察。但是,路径表达式可以与NUMBER
或FLOAT
一起使用。