|
1 | | -""" |
2 | | -A parser for navigating and extracting data from FHIR JSON resources. |
3 | | -
|
4 | | -Identifiy a path to a node using '|' to separate levels and |
5 | | -""" |
6 | | - |
7 | 1 | import json |
8 | 2 |
|
9 | 3 |
|
10 | 4 | class FHIRParser: |
11 | | - # parser variables |
12 | 5 | def __init__(self): |
13 | | - self.fhir_resource = {} |
| 6 | + self.fhir_resources = {} |
14 | 7 |
|
15 | | - # ------------------------------------------- |
16 | | - # File Management |
17 | | - # used for files |
18 | | - def parse_fhir_file(self, fhir_file_name): |
| 8 | + # This opens a file with FHIR resource data |
| 9 | + def parse_fhir_file(self, fhir_file_name: str) -> None: |
19 | 10 | with open(fhir_file_name) as json_file: |
20 | | - self.fhir_resource = json.load(json_file) |
| 11 | + self.fhir_resources = json.load(json_file) |
21 | 12 |
|
22 | | - # used for JSON FHIR Resource data |
23 | | - def parse_fhir_data(self, fhir_data): |
24 | | - self.fhir_resource = fhir_data |
| 13 | + # This is used for JSON FHIR Resource data events |
| 14 | + def parse_fhir_data(self, fhir_data: dict) -> None: |
| 15 | + self.fhir_resources = fhir_data |
25 | 16 |
|
26 | | - # ------------------------------------------------ |
27 | | - # Scan and Identify |
28 | | - # scan for a key name or a value |
29 | | - def _scan_values_for_match(self, parent, match_value): |
| 17 | + def _locate_fhir_item_in_dict(self, fhir_resource: dict, fhir_field: str) -> bool: |
| 18 | + """ |
| 19 | + Checks whether a given FHIR field name or value exists in a FHIR dictionary. |
| 20 | + :param fhir_resource: The FHIR resource as a dictionary. |
| 21 | + :param fhir_field: The FHIR field name or value to search for. |
| 22 | + :return: True if the field name or value matches a key item in the resource, False otherwise. |
| 23 | + """ |
30 | 24 | try: |
31 | | - for key in parent: |
32 | | - if parent[key] == match_value: |
| 25 | + for key in fhir_resource: |
| 26 | + if fhir_resource[key] == fhir_field: |
33 | 27 | return True |
34 | 28 | return False |
35 | 29 | except Exception: |
36 | 30 | return False |
37 | 31 |
|
38 | | - # locate an index for an item in a list |
39 | | - def _locate_list_id(self, parent, locator): |
40 | | - field_list = locator.split(":") |
| 32 | + def _locate_fhir_item_in_list(self, fhir_resource: list, fhir_field: str) -> dict: |
| 33 | + """ |
| 34 | + Locates and returns the first FHIR item (dictionary) in a list that contains |
| 35 | + the specified FHIR field name or value. |
| 36 | + :param fhir_resource: The FHIR resource as a list of dictionaries. |
| 37 | + :param fhir_field: The FHIR field name or value to search for. |
| 38 | + :return: The first matching FHIR item (dictionary) if found, otherwise an empty string. |
| 39 | + """ |
| 40 | + field_list = fhir_field.split(":") |
41 | 41 | node_id = 0 |
42 | 42 | index = 0 |
43 | 43 | try: |
44 | | - while index < len(parent): |
45 | | - for key in parent[index]: |
46 | | - if (parent[index][key] == field_list[1]) or (key == field_list[1]): |
| 44 | + while index < len(fhir_resource): |
| 45 | + for key in fhir_resource[index]: |
| 46 | + if (fhir_resource[index][key] == field_list[1]) or (key == field_list[1]): |
47 | 47 | node_id = index |
48 | 48 | break |
49 | 49 | else: |
50 | | - if self._scan_values_for_match(parent[index][key], field_list[1]): |
| 50 | + if self._locate_fhir_item_in_dict(fhir_resource[index][key], field_list[1]): |
51 | 51 | node_id = index |
52 | 52 | break |
53 | 53 | index += 1 |
54 | 54 | except Exception: |
55 | 55 | return "" |
56 | | - return parent[node_id] |
| 56 | + return fhir_resource[node_id] |
57 | 57 |
|
58 | 58 | # identify a node in the FHIR data |
59 | | - def _get_node(self, parent, child): |
60 | | - # check for indices |
| 59 | + def _extract_fhir_node_value(self, fhir_resource: dict | list, fhir_field_key: str) -> str: |
| 60 | + """ |
| 61 | + Safely retrieves a value from a FHIR resource by key or index. |
| 62 | + :param fhir_resource: The FHIR resource, which can be a dictionary or a list. |
| 63 | + :param fhir_field_key: The key (string) or index (integer as string) to retrieve the value for. |
| 64 | + :return: The value associated with the key or index, or an empty string if not found. |
| 65 | + """ |
61 | 66 | try: |
62 | | - result = parent[child] |
| 67 | + result = fhir_resource[fhir_field_key] |
63 | 68 | except Exception: |
64 | 69 | try: |
65 | | - child = int(child) |
66 | | - result = parent[child] |
| 70 | + child = int(fhir_field_key) |
| 71 | + result = fhir_resource[child] |
67 | 72 | except Exception: |
68 | 73 | result = "" |
69 | 74 | return result |
70 | 75 |
|
71 | | - # locate a value for a key |
72 | | - def _scan_for_value(self, fhir_fields): |
73 | | - field_list = fhir_fields.split("|") |
| 76 | + def _resolve_fhir_path(self, fhir_field_path: str) -> str: |
| 77 | + """ |
| 78 | + Resolves a FHIR value from a pipe-delimited FHIR path string. |
| 79 | + This function navigates through FHIR resources stored in `self.fhir_resources` |
| 80 | + using the provided path, which may include nested dictionaries or lists. |
| 81 | + Fields prefixed with "#" indicate list-based lookups. |
| 82 | + """ |
| 83 | + field_list = fhir_field_path.split("|") |
| 84 | + |
74 | 85 | # get root field before we iterate |
75 | | - rootfield = self.fhir_resource[field_list[0]] |
| 86 | + resource_per_field = self.fhir_resources[field_list[0]] |
76 | 87 | del field_list[0] |
77 | 88 | try: |
78 | 89 | for field in field_list: |
79 | 90 | if field.startswith("#"): |
80 | | - rootfield = self._locate_list_id(rootfield, field) # check here for default index?? |
| 91 | + resource_per_field = self._locate_fhir_item_in_list( |
| 92 | + resource_per_field, field |
| 93 | + ) # check here for default index?? |
81 | 94 | else: |
82 | | - rootfield = self._get_node(rootfield, field) |
| 95 | + resource_per_field = self._extract_fhir_node_value(resource_per_field, field) |
83 | 96 | except Exception: |
84 | | - rootfield = "" |
85 | | - return rootfield |
| 97 | + resource_per_field = "" |
| 98 | + return resource_per_field |
86 | 99 |
|
87 | | - # get the value list for a key |
88 | | - def get_key_value(self, field_name): |
| 100 | + def get_fhir_value_list(self, field_path: str) -> list[str]: |
| 101 | + """ |
| 102 | + Retrieves one or more values from a FHIR resource and returns them as a list. |
| 103 | + :param field_path: The FHIR field path to retrieve the values for. |
| 104 | + :return: A list of values found at the specified FHIR field path. |
| 105 | + """ |
89 | 106 | value = [] |
90 | 107 | try: |
91 | | - response_value = self._scan_for_value(field_name) |
| 108 | + response_value = self._resolve_fhir_path(field_path) |
92 | 109 | except Exception: |
93 | 110 | response_value = "" |
94 | 111 |
|
95 | 112 | value.append(response_value) |
96 | 113 | return value |
97 | 114 |
|
98 | | - # get the value list for a key |
99 | | - def get_key_single_value(self, field_name): |
| 115 | + def get_fhir_value(self, field_path: str) -> str: |
| 116 | + """ |
| 117 | + Retrieves a single value from a FHIR resource. |
| 118 | + :param field_path: The FHIR field path to retrieve the value for. |
| 119 | + :return: The value as a string, or an empty string if not found. |
| 120 | + """ |
100 | 121 | value = "" |
101 | 122 | try: |
102 | | - response_value = self._scan_for_value(field_name) |
| 123 | + response_value = self._resolve_fhir_path(field_path) |
103 | 124 | except Exception: |
104 | 125 | response_value = "" |
105 | 126 |
|
|
0 commit comments