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

如何修改Prolog的json_get谓词以支持数组索引查询?

Extending json_get to Handle JSON Arrays and Nested Paths

Great question! Your current json_get works perfectly for grabbing top-level fields from JSON objects, but it doesn't know how to handle JSON arrays or nested paths (like digging into an array that's a value of an object field). Let's fix that by adding support for array indices and recursive path traversal.

First, let's rewrite the predicate to handle three key scenarios:

  1. Fetching a field from a JSON object
  2. Fetching an element from a JSON array by index
  3. Recursively traversing a nested path of fields and indices

Here's the modified code:

% Grab a value from a JSON object using an atom field name
json_get(json_obj(JSON_obj), Field, Result) :-
    atom(Field),
    memberchk((Field, Result), JSON_obj).

% Grab an element from a JSON array using a 0-based integer index
json_get(json_array(JSON_arr), Index, Result) :-
    integer(Index),
    nth0(Index, JSON_arr, Result).

% Recursively walk through a nested path (mix of fields and indices)
json_get(JSON, [Step|Rest], Result) :-
    json_get(JSON, Step, Intermediate),
    json_get(Intermediate, Rest, Result).

% Optional: Empty path returns the original JSON (useful for edge cases)
json_get(JSON, [], JSON).

What Changed?

  • Array Support: We added a new clause that checks if we're dealing with a json_array and an integer index. We used nth0/3 for 0-based indexing (so index 0 gets the first element, 1 gets the second, etc.). If you prefer 1-based indexing (where 1 is the first element), just swap nth0 with nth1.
  • Nested Paths: The recursive clause lets you pass a list of steps (like ["heads", 1]) to dig into nested structures. First it grabs the heads array from the object, then pulls the element at index 1 from that array.
  • Avoid Ambiguity: We added checks like atom(Field) and integer(Index) to make sure the predicate knows whether it's dealing with an object field or an array index.

Testing It Out

Let's run your example query:

json_parse('{"nome" : "Zaphod", "heads" : ["Head1", "Head2"]}', Z),
json_get(Z, ["heads", 1], R).

This should return R = "Head2" (since we're using 0-based indexing). If you wanted Head1 instead, just use index 0.

A quick note about your original working query: the behavior shifts a little with the modified code. Originally, json_get(O, ["nome"], R) would return R = ["Arthur"] (a list of results from maplist). Now it returns R = "Arthur" directly (since it treats ["nome"] as a nested path with one step). If you still want to grab multiple top-level fields as a list, just use maplist(json_get(O), ["nome", "cognome"], R) directly—it'll give you R = ["Arthur", "Dent"] just like before.

Bonus: Keep Both Behaviors

If you want to retain the original ability to fetch multiple top-level fields with a list while adding nested path support, add this extra clause:

% Handle lists of top-level fields (original behavior)
json_get(JSON_obj, Fields, Results) :-
    is_list(Fields),
    forall(member(F, Fields), atom(F)), % Make sure all elements are field names
    maplist(json_get(JSON_obj), Fields, Results).

Now json_get(O, ["nome", "cognome"], R) returns R = ["Arthur", "Dent"], and json_get(Z, ["heads", 1], R) still gives you R = "Head2"—best of both worlds!

Content of the question originates from Stack Exchange, question author Giuseppe Giubaldo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:58:15