Skip to content

Instantly share code, notes, and snippets.

@mikerj1
Last active August 30, 2024 18:22
Show Gist options
  • Save mikerj1/1d7098defbd0a9db9332311646220dee to your computer and use it in GitHub Desktop.
Save mikerj1/1d7098defbd0a9db9332311646220dee to your computer and use it in GitHub Desktop.

Revisions

  1. mikerj1 revised this gist Aug 30, 2024. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions find-json-path.py
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,17 @@
    #!/usr/bin/env python3
    # Copyright 2024 Mike Johnson
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    # http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.

    import json
    import sys
  2. mikerj1 created this gist Aug 30, 2024.
    87 changes: 87 additions & 0 deletions find-json-path.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,87 @@
    #!/usr/bin/env python3

    import json
    import sys
    import re
    import argparse

    def find_key_paths(data, target_key, path="", mode="exact"):
    paths = []
    if isinstance(data, dict):
    for key, value in data.items():
    new_path = f"{path}.{key}" if path else key
    if (
    (mode == "exact" and key == target_key) or
    (mode == "substring" and target_key in key) or
    (mode == "regex" and re.search(target_key, key))
    ):
    paths.append(new_path)
    paths.extend(find_key_paths(value, target_key, new_path, mode))
    elif isinstance(data, list):
    for index, item in enumerate(data):
    new_path = f"{path}[{index}]"
    paths.extend(find_key_paths(item, target_key, new_path, mode))
    return paths

    def main():
    parser = argparse.ArgumentParser(description="Search for keys in a JSON file.")
    parser.add_argument("--exact", "-e", action="store_true", help="Search for exact key match")
    parser.add_argument("--substring", "-s", action="store_true", help="Search for key as substring")
    parser.add_argument("--regex", "-r", action="store_true", help="Search for key using regex")
    parser.add_argument("--key", "-k", "--term", "-t", type=str, help="The key or term to search for")
    parser.add_argument("--file", "-f", type=str, help="The JSON file to search in")
    parser.add_argument("file_positional", nargs="?", help="Positional argument for the JSON file if --file/-f is not used")

    args = parser.parse_args()

    # Determine the search mode
    if args.exact or args.exact == "ex":
    search_mode = "exact"
    elif args.substring or args.substring == "sub":
    search_mode = "substring"
    elif args.regex or args.regex == "re":
    search_mode = "regex"
    else:
    search_mode = None

    # Determine the JSON file
    json_file = args.file or args.file_positional

    if args.key:
    target_key = args.key
    else:
    target_key = None

    # If no command-line arguments provided, fall back to interactive mode
    if not search_mode or not target_key or not json_file:
    print("Entering interactive mode...")
    target_key = target_key or input("Enter the key to search for: ")
    search_mode = search_mode or input("Search mode (exact/ex, substring/sub, regex/re): ").strip().lower()

    # Map abbreviations to full search mode
    if search_mode in {"ex", "exact"}:
    search_mode = "exact"
    elif search_mode in {"sub", "substring"}:
    search_mode = "substring"
    elif search_mode in {"re", "regex"}:
    search_mode = "regex"
    else:
    print("Invalid search mode. Please choose 'exact/ex', 'substring/sub', or 'regex/re'.")
    sys.exit(1)

    json_file = json_file or input("Enter the path to the JSON file: ")

    with open(json_file, 'r') as file:
    data = json.load(file)

    paths = find_key_paths(data, target_key, mode=search_mode)

    if paths:
    print(f"Paths to keys matching '{target_key}':")
    for path in paths:
    print(path)
    else:
    print(f"No keys matching '{target_key}' found in the JSON.")

    if __name__ == "__main__":
    main()