Here is a Python solution that parses the JSON files, builds a merged data structure, and provides the interactive drill-down menu you requested.

The Python Script

This script assumes your JSON files are in the current directory (or you can modify search_path). It uses a recursive merge strategy so that if you have multiple files adding data to the same Platform, they combine rather than overwrite each other.

Python

import json
import glob
import os

def load_and_merge_data(search_path="*.json"):
    """
    Scans for JSON files and merges them into a single master dictionary.
    """
    master_data = {}
    files = glob.glob(search_path)
    
    if not files:
        print("No JSON files found in the current directory.")
        return {}

    print(f"Found {len(files)} files. Parsing...")

    for file_path in files:
        try:
            with open(file_path, 'r') as f:
                data = json.load(f)
                # Deep merge the new data into master_data
                deep_merge(data, master_data)
        except json.JSONDecodeError:
            print(f"Error decoding JSON in file: {file_path}")
        except Exception as e:
            print(f"Error reading {file_path}: {e}")

    return master_data

def deep_merge(source, destination):
    """
    Recursively merges source dict into destination dict.
    """
    for key, value in source.items():
        if isinstance(value, dict):
            # Get the node or create it if it doesn't exist
            node = destination.setdefault(key, {})
            deep_merge(value, node)
        else:
            # For lists (files/folders) or primitives (strings), we overwrite 
            # or we could extend lists. Here we overwrite for simplicity based on your schema.
            destination[key] = value
    return destination

def get_user_selection(options, label):
    """
    Helper to present a numbered list and get a valid index from the user.
    """
    if not options:
        print(f"No {label} options available.")
        return None

    print(f"\n--- Select {label} ---")
    sorted_options = sorted(list(options))
    
    for idx, option in enumerate(sorted_options):
        print(f"{idx + 1}. {option}")

    while True:
        try:
            selection = input(f"\nEnter number for {label}: ")
            idx = int(selection) - 1
            if 0 <= idx < len(sorted_options):
                return sorted_options[idx]
            else:
                print(f"Please enter a number between 1 and {len(sorted_options)}.")
        except ValueError:
            print("Invalid input. Please enter an integer.")

def main():
    # 1. Load Data
    data_tree = load_and_merge_data()
    
    if not data_tree:
        return

    # 2. Select Platform
    # The top-level keys in your JSON are the platforms (e.g., 'myNodeMCU')
    selected_platform = get_user_selection(data_tree.keys(), "Platform")
    if not selected_platform: return

    # 3. Select Platform Type
    # Keys under the platform (e.g., 'nodemcu-firmware')
    platform_node = data_tree[selected_platform]
    selected_type = get_user_selection(platform_node.keys(), "Platform Type")
    if not selected_type: return

    # 4. Select Skeleton
    # Keys under the type (e.g., 'ld')
    type_node = platform_node[selected_type]
    selected_skeleton = get_user_selection(type_node.keys(), "Skeleton")
    if not selected_skeleton: return

    # 5. Retrieve and Display Files
    # Access the final node
    final_node = type_node[selected_skeleton]
    
    # Extract the file list
    file_list = final_node.get('files', [])
    
    print(f"\n=== Results for {selected_platform} > {selected_type} > {selected_skeleton} ===")
    if file_list:
        print("Files found:")
        for f in file_list:
            print(f" - {f}")
    else:
        print("No files found in this selection.")

if __name__ == "__main__":
    main()

How It Works

  1. deep_merge Function: Since you might have multiple JSON files (e.g., one for ld skeleton and another for a different skeleton under the same platform), we cannot simply overwrite the dictionary. This function recursively navigates the keys. If myNodeMCU exists, it goes inside and adds the new data rather than deleting what was already there.
  2. Menu Structure:
    • Platform: Reads the root keys of the merged dictionary (e.g., myNodeMCU).
    • Platform Type: Reads the keys immediately under the selected Platform (e.g., nodemcu-firmware).
    • Skeleton: Reads the keys immediately under the selected Type (e.g., ld).
  3. Result: Once the user drills down to the specific skeleton, the script looks for the files key list and prints the contents (e.g., defsym.rom, nodemcu.ld).

How to test this

To verify this works immediately, create a file named test_data.json in the same folder as the script and paste your provided JSON content into it:

JSON

{
    "myNodeMCU": {
        "nodemcu-firmware": {
            "ld": {
                "meta": {
                    "root_id": "a8ae315d",
                    "platform": "myNodeMCU",
                    "platform_type": "nodemcu-firmware",
                    "skeleton": "ld"
                },
                "folders": [],
                "files": [
                    "defsym.rom",
                    "nodemcu.ld"
                ]
            }
        }
    }
}

Leave a Reply