Python中如何通过带过滤条件的JSONPath更新节点?
问题
需要通过带过滤条件的JSONPath(例如包含[@.field]的表达式)更新JSON节点,但使用jsonpath_ng库的尝试均未成功。以下是测试代码及运行输出:
测试代码
import json import jsonpath_ng.ext import jsonpath_ng from hashlib import md5 # 尝试将 {"a": {"b": "c"}} 转为 {"a": {1: 2}} for jpath_str in ["$.a", "$[?(@.b)]", "$.a.b.`parent`"]: for jp_lib in [jsonpath_ng, jsonpath_ng.ext]: obj = json.loads('{"a": {"b": "c"}}') print(f"jp_lib={jp_lib.__name__:<15} json_path_str={jpath_str:<15}", end="\t") try: # 查找节点并尝试更新 jpath = jp_lib.parse(jpath_str) matches = jpath.find(obj) if not matches: print("--> 未找到节点") continue for match in matches: print(f"match={md5(str(match).encode()).hexdigest()[:-10]}", end="\t") jpath.update(obj, {1:2}) print(f"--> 结果={obj}", end="\t") if "b" in obj['a']: print(" -->更新静默失败", end="\t") except Exception as ex: print(f"--> 异常={type(ex).__name__}({ex})") print()
运行输出
jp_lib=jsonpath_ng json_path_str=$.a match=6d6c26aced0709ca568e84 --> 结果={'a': {1: 2}} jp_lib=jsonpath_ng.ext json_path_str=$.a match=6d6c26aced0709ca568e84 --> 结果={'a': {1: 2}} jp_lib=jsonpath_ng json_path_str=$[?(@.b)] --> 异常=JsonPathLexerError(Error on line 1, col 2: Unexpected character: ? ) jp_lib=jsonpath_ng.ext json_path_str=$[?(@.b)] match=6de1848d9db98d7d1c6766 --> 结果={'a': {'b': 'c'}} -->更新静默失败 jp_lib=jsonpath_ng json_path_str=$.a.b.`parent` match=6d6c26aced0709ca568e84 --> 异常=NotImplementedError() jp_lib=jsonpath_ng.ext json_path_str=$.a.b.`parent` match=6d6c26aced0709ca568e84 --> 异常=NotImplementedError()
问题分析与解决方案
- 基础路径
$.a更新正常:不管是jsonpath_ng还是jsonpath_ng.ext,直接定位到节点a时,update方法能正常替换值,符合预期。 - 过滤路径
$[?(@.b)]失效:- 原生
jsonpath_ng不支持过滤表达式([?()]),会直接抛出语法错误。 jsonpath_ng.ext能找到匹配的节点,但update方法无法生效。这是因为过滤表达式匹配的是整个根对象$,而非a节点,调用update会尝试替换根对象,但传入的{1:2}并没有覆盖a,导致原节点保留。
解决方法:调整过滤路径为$.a[?(@.b)],直接定位到包含b字段的a节点,这样update就能正确替换a的值。
- 原生
parent语法未实现:不管哪个库,$.a.b.parent``语法都未实现,抛出NotImplementedError,暂时无法通过这种方式获取父节点并更新,建议直接定位目标节点或调整路径。
内容的提问来源于stack exchange,提问作者IndustryUser1942
相关产品推荐
相关产品推荐

