nchandu2023 commited on
Commit
5960b3d
·
verified ·
1 Parent(s): f207c28

Update responseparser.py (#5)

Browse files

- Update responseparser.py (c55e3b0fd1ba42e21dce494341108786bcffdb1a)

Files changed (1) hide show
  1. responseparser.py +112 -110
responseparser.py CHANGED
@@ -1,21 +1,23 @@
1
- import json
2
  from datetime import datetime
3
  from typing import List, Dict, Optional, Union
4
 
5
  class PatientDataExtractor:
6
- """Class to extract all fields from a FHIR Patient resource in a Bundle response."""
7
 
8
  def __init__(self, patient_data: str):
9
- """Initialize with patient data in JSON string format."""
10
- self.data = json.loads(patient_data) if isinstance(patient_data, str) else patient_data
 
 
 
11
  self.patients = self._extract_patients()
12
  self.current_patient_idx = 0 # Default to first patient
13
 
14
- def _extract_patients(self) -> List[Dict]:
15
  """Extract all patient entries from the Bundle."""
16
- if self.data.get("resourceType") != "Bundle" or "entry" not in self.data:
17
- raise ValueError("Invalid FHIR Bundle format")
18
- return [entry["resource"] for entry in self.data["entry"] if entry["resource"]["resourceType"] == "Patient"]
19
 
20
  def set_patient_by_index(self, index: int) -> bool:
21
  """Set the current patient by index. Returns True if successful."""
@@ -27,86 +29,101 @@ class PatientDataExtractor:
27
  def set_patient_by_id(self, patient_id: str) -> bool:
28
  """Set the current patient by FHIR Patient ID. Returns True if successful."""
29
  for i, patient in enumerate(self.patients):
30
- if patient["id"] == patient_id:
31
  self.current_patient_idx = i
32
  return True
33
  return False
34
 
35
- def _get_current_patient(self) -> Dict:
36
  """Get the currently selected patient resource."""
37
  return self.patients[self.current_patient_idx]
38
 
39
  # Basic Identification Fields
40
  def get_id(self) -> str:
41
  """Extract FHIR Patient ID."""
42
- return self._get_current_patient().get("id", "")
43
 
44
  def get_resource_type(self) -> str:
45
  """Extract resource type (should always be 'Patient')."""
46
- return self._get_current_patient().get("resourceType", "")
47
 
48
  def get_meta_last_updated(self) -> str:
49
  """Extract last updated timestamp from meta."""
50
- return self._get_current_patient().get("meta", {}).get("lastUpdated", "")
 
 
51
 
52
  def get_meta_profile(self) -> List[str]:
53
  """Extract profile URIs from meta."""
54
- return self._get_current_patient().get("meta", {}).get("profile", [])
 
 
55
 
56
  def get_text_div(self) -> str:
57
  """Extract generated text narrative (div content)."""
58
- return self._get_current_patient().get("text", {}).get("div", "")
 
 
 
 
59
 
60
  # Name Fields
61
  def get_first_name(self) -> str:
62
  """Extract patient's first name."""
63
  patient = self._get_current_patient()
64
- names = patient.get("name", [])
65
- for name in names:
66
- if name.get("use") == "official" and "given" in name:
67
- return name["given"][0]
 
68
  return ""
69
 
70
  def get_last_name(self) -> str:
71
  """Extract patient's last name."""
72
  patient = self._get_current_patient()
73
- names = patient.get("name", [])
74
- for name in names:
75
- if name.get("use") == "official" and "family" in name:
76
- return name["family"]
 
77
  return ""
78
 
79
  def get_middle_initial(self) -> str:
80
  """Extract patient's middle initial (second given name initial if present)."""
81
  patient = self._get_current_patient()
82
- names = patient.get("name", [])
83
- for name in names:
84
- if name.get("use") == "official" and "given" in name and len(name["given"]) > 1:
85
- return name["given"][1][0]
 
86
  return ""
87
 
88
  def get_name_prefix(self) -> str:
89
  """Extract patient's name prefix (e.g., Mr., Mrs.)."""
90
  patient = self._get_current_patient()
91
- names = patient.get("name", [])
92
- for name in names:
93
- if name.get("use") == "official" and "prefix" in name:
94
- return name["prefix"][0]
 
95
  return ""
96
 
97
  def get_maiden_name(self) -> str:
98
  """Extract patient's maiden name if available."""
99
  patient = self._get_current_patient()
100
- names = patient.get("name", [])
101
- for name in names:
102
- if name.get("use") == "maiden" and "family" in name:
103
- return name["family"]
 
104
  return ""
105
 
106
  # Demographic Fields
107
  def get_dob(self) -> str:
108
  """Extract patient's date of birth."""
109
- return self._get_current_patient().get("birthDate", "")
 
 
110
 
111
  def get_age(self) -> str:
112
  """Calculate patient's age based on birth date."""
@@ -120,160 +137,145 @@ class PatientDataExtractor:
120
 
121
  def get_gender(self) -> str:
122
  """Extract patient's gender."""
123
- return self._get_current_patient().get("gender", "").capitalize()
 
 
124
 
125
  def get_birth_sex(self) -> str:
126
  """Extract patient's birth sex from extensions."""
127
  patient = self._get_current_patient()
128
- for ext in patient.get("extension", []):
129
- if ext.get("url") == "http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex":
130
- return ext.get("valueCode", "")
131
- return ""
132
 
133
  def get_multiple_birth(self) -> Union[bool, None]:
134
  """Extract multiple birth status."""
135
- return self._get_current_patient().get("multipleBirthBoolean", None)
 
 
136
 
137
  # Address Fields
138
  def get_address_line(self) -> str:
139
  """Extract patient's street address."""
140
  patient = self._get_current_patient()
141
- addresses = patient.get("address", [])
142
- return addresses[0]["line"][0] if addresses and "line" in addresses[0] else ""
143
 
144
  def get_city(self) -> str:
145
  """Extract patient's city."""
146
  patient = self._get_current_patient()
147
- addresses = patient.get("address", [])
148
- return addresses[0]["city"] if addresses and "city" in addresses[0] else ""
149
 
150
  def get_state(self) -> str:
151
  """Extract patient's state."""
152
  patient = self._get_current_patient()
153
- addresses = patient.get("address", [])
154
- return addresses[0]["state"] if addresses and "state" in addresses[0] else ""
155
 
156
  def get_zip_code(self) -> str:
157
  """Extract patient's postal code."""
158
  patient = self._get_current_patient()
159
- addresses = patient.get("address", [])
160
- return addresses[0]["postalCode"] if addresses and "postalCode" in addresses[0] else ""
161
 
162
  def get_country(self) -> str:
163
  """Extract patient's country."""
164
  patient = self._get_current_patient()
165
- addresses = patient.get("address", [])
166
- return addresses[0]["country"] if addresses and "country" in addresses[0] else ""
167
 
168
  def get_geolocation(self) -> Dict[str, float]:
169
  """Extract geolocation (latitude and longitude) from address extension."""
170
  patient = self._get_current_patient()
171
- addresses = patient.get("address", [])
172
- if not addresses:
173
- return {"latitude": None, "longitude": None}
174
- for ext in addresses[0].get("extension", []):
175
- if ext.get("url") == "http://hl7.org/fhir/StructureDefinition/geolocation":
176
- geo = {}
177
- for sub_ext in ext.get("extension", []):
178
- if sub_ext.get("url") == "latitude":
179
- geo["latitude"] = sub_ext.get("valueDecimal")
180
- elif sub_ext.get("url") == "longitude":
181
- geo["longitude"] = sub_ext.get("valueDecimal")
182
- return geo
183
- return {"latitude": None, "longitude": None}
184
 
185
  # Contact Fields
186
  def get_phone(self) -> str:
187
  """Extract patient's phone number."""
188
  patient = self._get_current_patient()
189
- telecoms = patient.get("telecom", [])
190
- for telecom in telecoms:
191
- if telecom.get("system") == "phone" and telecom.get("use") == "home":
192
- return telecom.get("value", "")
193
- return ""
194
 
195
  # Identifiers
196
  def get_identifiers(self) -> Dict[str, str]:
197
  """Extract all identifiers (e.g., SSN, MRN, Driver's License)."""
198
  patient = self._get_current_patient()
199
- identifiers = patient.get("identifier", [])
200
  id_dict = {}
 
201
  for id_entry in identifiers:
202
- id_type = id_entry.get("type", {}).get("text", "Unknown")
203
- id_dict[id_type] = id_entry.get("value", "")
 
 
204
  return id_dict
205
 
206
  # Extensions
207
  def get_race(self) -> str:
208
  """Extract patient's race from extensions."""
209
  patient = self._get_current_patient()
210
- for ext in patient.get("extension", []):
211
- if ext.get("url") == "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race":
212
- for sub_ext in ext.get("extension", []):
213
- if sub_ext.get("url") == "text":
214
- return sub_ext.get("valueString", "")
215
- return ""
216
 
217
  def get_ethnicity(self) -> str:
218
  """Extract patient's ethnicity from extensions."""
219
  patient = self._get_current_patient()
220
- for ext in patient.get("extension", []):
221
- if ext.get("url") == "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity":
222
- for sub_ext in ext.get("extension", []):
223
- if sub_ext.get("url") == "text":
224
- return sub_ext.get("valueString", "")
225
- return ""
226
 
227
  def get_mothers_maiden_name(self) -> str:
228
  """Extract patient's mother's maiden name from extensions."""
229
  patient = self._get_current_patient()
230
- for ext in patient.get("extension", []):
231
- if ext.get("url") == "http://hl7.org/fhir/StructureDefinition/patient-mothersMaidenName":
232
- return ext.get("valueString", "")
233
- return ""
234
 
235
  def get_birth_place(self) -> Dict[str, str]:
236
  """Extract patient's birth place from extensions."""
237
  patient = self._get_current_patient()
238
- for ext in patient.get("extension", []):
239
- if ext.get("url") == "http://hl7.org/fhir/StructureDefinition/patient-birthPlace":
240
- addr = ext.get("valueAddress", {})
241
- return {
242
- "city": addr.get("city", ""),
243
- "state": addr.get("state", ""),
244
- "country": addr.get("country", "")
245
- }
 
 
246
  return {"city": "", "state": "", "country": ""}
247
 
248
  def get_disability_adjusted_life_years(self) -> Optional[float]:
249
  """Extract disability-adjusted life years from extensions."""
250
  patient = self._get_current_patient()
251
- for ext in patient.get("extension", []):
252
- if ext.get("url") == "http://synthetichealth.github.io/synthea/disability-adjusted-life-years":
253
- return ext.get("valueDecimal")
254
- return None
255
 
256
  def get_quality_adjusted_life_years(self) -> Optional[float]:
257
  """Extract quality-adjusted life years from extensions."""
258
  patient = self._get_current_patient()
259
- for ext in patient.get("extension", []):
260
- if ext.get("url") == "http://synthetichealth.github.io/synthea/quality-adjusted-life-years":
261
- return ext.get("valueDecimal")
262
- return None
263
 
264
  # Marital Status
265
  def get_marital_status(self) -> str:
266
  """Extract patient's marital status."""
267
  patient = self._get_current_patient()
268
- status = patient.get("maritalStatus", {}).get("text", "")
269
- return status if status else patient.get("maritalStatus", {}).get("coding", [{}])[0].get("display", "")
 
 
 
270
 
271
  # Communication
272
  def get_language(self) -> str:
273
  """Extract patient's preferred language."""
274
  patient = self._get_current_patient()
275
- comms = patient.get("communication", [])
276
- return comms[0]["language"]["text"] if comms and "language" in comms[0] else ""
277
 
278
  # Comprehensive Extraction
279
  def get_all_patient_data(self) -> Dict[str, Union[str, Dict, List, float, bool, None]]:
@@ -359,7 +361,7 @@ class PatientDataExtractor:
359
 
360
  def get_patient_ids(self) -> List[str]:
361
  """Return a list of all patient IDs in the Bundle."""
362
- return [patient["id"] for patient in self.patients]
363
 
364
  # # Example usage with integration into app.py
365
  # def integrate_with_app(patient_data: str):
 
1
+ import lxml.etree as etree
2
  from datetime import datetime
3
  from typing import List, Dict, Optional, Union
4
 
5
  class PatientDataExtractor:
6
+ """Class to extract all fields from a FHIR Patient resource in a Bundle response (XML format)."""
7
 
8
  def __init__(self, patient_data: str):
9
+ """Initialize with patient data in XML string format."""
10
+ # Parse XML string or use pre-parsed data
11
+ self.data = etree.fromstring(patient_data) if isinstance(patient_data, str) else patient_data
12
+ # Define FHIR namespace for XPath queries
13
+ self.ns = {'fhir': 'http://hl7.org/fhir'}
14
  self.patients = self._extract_patients()
15
  self.current_patient_idx = 0 # Default to first patient
16
 
17
+ def _extract_patients(self) -> List[etree._Element]:
18
  """Extract all patient entries from the Bundle."""
19
+ # Use XPath to find all Patient elements in the Bundle
20
+ return self.data.xpath("//fhir:entry/fhir:resource/fhir:Patient", namespaces=self.ns)
 
21
 
22
  def set_patient_by_index(self, index: int) -> bool:
23
  """Set the current patient by index. Returns True if successful."""
 
29
  def set_patient_by_id(self, patient_id: str) -> bool:
30
  """Set the current patient by FHIR Patient ID. Returns True if successful."""
31
  for i, patient in enumerate(self.patients):
32
+ if patient.attrib.get("id") == patient_id:
33
  self.current_patient_idx = i
34
  return True
35
  return False
36
 
37
+ def _get_current_patient(self) -> etree._Element:
38
  """Get the currently selected patient resource."""
39
  return self.patients[self.current_patient_idx]
40
 
41
  # Basic Identification Fields
42
  def get_id(self) -> str:
43
  """Extract FHIR Patient ID."""
44
+ return self._get_current_patient().attrib.get("id", "")
45
 
46
  def get_resource_type(self) -> str:
47
  """Extract resource type (should always be 'Patient')."""
48
+ return etree.QName(self._get_current_patient().tag).localname
49
 
50
  def get_meta_last_updated(self) -> str:
51
  """Extract last updated timestamp from meta."""
52
+ patient = self._get_current_patient()
53
+ last_updated = patient.xpath("fhir:meta/fhir:lastUpdated/@value", namespaces=self.ns)
54
+ return last_updated[0] if last_updated else ""
55
 
56
  def get_meta_profile(self) -> List[str]:
57
  """Extract profile URIs from meta."""
58
+ patient = self._get_current_patient()
59
+ profiles = patient.xpath("fhir:meta/fhir:profile/@value", namespaces=self.ns)
60
+ return profiles
61
 
62
  def get_text_div(self) -> str:
63
  """Extract generated text narrative (div content)."""
64
+ patient = self._get_current_patient()
65
+ div = patient.xpath("fhir:text/fhir:div", namespaces=self.ns)
66
+ if div:
67
+ return etree.tostring(div[0], encoding="unicode")
68
+ return ""
69
 
70
  # Name Fields
71
  def get_first_name(self) -> str:
72
  """Extract patient's first name."""
73
  patient = self._get_current_patient()
74
+ official_names = patient.xpath("fhir:name[fhir:use/@value='official']", namespaces=self.ns)
75
+ if official_names:
76
+ given = official_names[0].xpath("fhir:given/@value", namespaces=self.ns)
77
+ if given:
78
+ return given[0]
79
  return ""
80
 
81
  def get_last_name(self) -> str:
82
  """Extract patient's last name."""
83
  patient = self._get_current_patient()
84
+ official_names = patient.xpath("fhir:name[fhir:use/@value='official']", namespaces=self.ns)
85
+ if official_names:
86
+ family = official_names[0].xpath("fhir:family/@value", namespaces=self.ns)
87
+ if family:
88
+ return family[0]
89
  return ""
90
 
91
  def get_middle_initial(self) -> str:
92
  """Extract patient's middle initial (second given name initial if present)."""
93
  patient = self._get_current_patient()
94
+ official_names = patient.xpath("fhir:name[fhir:use/@value='official']", namespaces=self.ns)
95
+ if official_names:
96
+ given = official_names[0].xpath("fhir:given/@value", namespaces=self.ns)
97
+ if len(given) > 1:
98
+ return given[1][0]
99
  return ""
100
 
101
  def get_name_prefix(self) -> str:
102
  """Extract patient's name prefix (e.g., Mr., Mrs.)."""
103
  patient = self._get_current_patient()
104
+ official_names = patient.xpath("fhir:name[fhir:use/@value='official']", namespaces=self.ns)
105
+ if official_names:
106
+ prefix = official_names[0].xpath("fhir:prefix/@value", namespaces=self.ns)
107
+ if prefix:
108
+ return prefix[0]
109
  return ""
110
 
111
  def get_maiden_name(self) -> str:
112
  """Extract patient's maiden name if available."""
113
  patient = self._get_current_patient()
114
+ maiden_names = patient.xpath("fhir:name[fhir:use/@value='maiden']", namespaces=self.ns)
115
+ if maiden_names:
116
+ family = maiden_names[0].xpath("fhir:family/@value", namespaces=self.ns)
117
+ if family:
118
+ return family[0]
119
  return ""
120
 
121
  # Demographic Fields
122
  def get_dob(self) -> str:
123
  """Extract patient's date of birth."""
124
+ patient = self._get_current_patient()
125
+ dob = patient.xpath("fhir:birthDate/@value", namespaces=self.ns)
126
+ return dob[0] if dob else ""
127
 
128
  def get_age(self) -> str:
129
  """Calculate patient's age based on birth date."""
 
137
 
138
  def get_gender(self) -> str:
139
  """Extract patient's gender."""
140
+ patient = self._get_current_patient()
141
+ gender = patient.xpath("fhir:gender/@value", namespaces=self.ns)
142
+ return gender[0].capitalize() if gender else ""
143
 
144
  def get_birth_sex(self) -> str:
145
  """Extract patient's birth sex from extensions."""
146
  patient = self._get_current_patient()
147
+ birth_sex = patient.xpath("fhir:extension[@url='http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex']/fhir:valueCode/@value", namespaces=self.ns)
148
+ return birth_sex[0] if birth_sex else ""
 
 
149
 
150
  def get_multiple_birth(self) -> Union[bool, None]:
151
  """Extract multiple birth status."""
152
+ patient = self._get_current_patient()
153
+ multiple_birth = patient.xpath("fhir:multipleBirthBoolean/@value", namespaces=self.ns)
154
+ return multiple_birth[0] == "true" if multiple_birth else None
155
 
156
  # Address Fields
157
  def get_address_line(self) -> str:
158
  """Extract patient's street address."""
159
  patient = self._get_current_patient()
160
+ line = patient.xpath("fhir:address/fhir:line/@value", namespaces=self.ns)
161
+ return line[0] if line else ""
162
 
163
  def get_city(self) -> str:
164
  """Extract patient's city."""
165
  patient = self._get_current_patient()
166
+ city = patient.xpath("fhir:address/fhir:city/@value", namespaces=self.ns)
167
+ return city[0] if city else ""
168
 
169
  def get_state(self) -> str:
170
  """Extract patient's state."""
171
  patient = self._get_current_patient()
172
+ state = patient.xpath("fhir:address/fhir:state/@value", namespaces=self.ns)
173
+ return state[0] if state else ""
174
 
175
  def get_zip_code(self) -> str:
176
  """Extract patient's postal code."""
177
  patient = self._get_current_patient()
178
+ postal_code = patient.xpath("fhir:address/fhir:postalCode/@value", namespaces=self.ns)
179
+ return postal_code[0] if postal_code else ""
180
 
181
  def get_country(self) -> str:
182
  """Extract patient's country."""
183
  patient = self._get_current_patient()
184
+ country = patient.xpath("fhir:address/fhir:country/@value", namespaces=self.ns)
185
+ return country[0] if country else ""
186
 
187
  def get_geolocation(self) -> Dict[str, float]:
188
  """Extract geolocation (latitude and longitude) from address extension."""
189
  patient = self._get_current_patient()
190
+ lat = patient.xpath("fhir:address/fhir:extension[@url='http://hl7.org/fhir/StructureDefinition/geolocation']/fhir:extension[@url='latitude']/fhir:valueDecimal/@value", namespaces=self.ns)
191
+ lon = patient.xpath("fhir:address/fhir:extension[@url='http://hl7.org/fhir/StructureDefinition/geolocation']/fhir:extension[@url='longitude']/fhir:valueDecimal/@value", namespaces=self.ns)
192
+ return {
193
+ "latitude": float(lat[0]) if lat else None,
194
+ "longitude": float(lon[0]) if lon else None
195
+ }
 
 
 
 
 
 
 
196
 
197
  # Contact Fields
198
  def get_phone(self) -> str:
199
  """Extract patient's phone number."""
200
  patient = self._get_current_patient()
201
+ phone = patient.xpath("fhir:telecom[fhir:system/@value='phone' and fhir:use/@value='home']/fhir:value/@value", namespaces=self.ns)
202
+ return phone[0] if phone else ""
 
 
 
203
 
204
  # Identifiers
205
  def get_identifiers(self) -> Dict[str, str]:
206
  """Extract all identifiers (e.g., SSN, MRN, Driver's License)."""
207
  patient = self._get_current_patient()
 
208
  id_dict = {}
209
+ identifiers = patient.xpath("fhir:identifier", namespaces=self.ns)
210
  for id_entry in identifiers:
211
+ id_type = id_entry.xpath("fhir:type/fhir:text/@value", namespaces=self.ns)
212
+ id_value = id_entry.xpath("fhir:value/@value", namespaces=self.ns)
213
+ if id_type and id_value:
214
+ id_dict[id_type[0]] = id_value[0]
215
  return id_dict
216
 
217
  # Extensions
218
  def get_race(self) -> str:
219
  """Extract patient's race from extensions."""
220
  patient = self._get_current_patient()
221
+ race = patient.xpath("fhir:extension[@url='http://hl7.org/fhir/us/core/StructureDefinition/us-core-race']/fhir:extension[@url='text']/fhir:valueString/@value", namespaces=self.ns)
222
+ return race[0] if race else ""
 
 
 
 
223
 
224
  def get_ethnicity(self) -> str:
225
  """Extract patient's ethnicity from extensions."""
226
  patient = self._get_current_patient()
227
+ ethnicity = patient.xpath("fhir:extension[@url='http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity']/fhir:extension[@url='text']/fhir:valueString/@value", namespaces=self.ns)
228
+ return ethnicity[0] if ethnicity else ""
 
 
 
 
229
 
230
  def get_mothers_maiden_name(self) -> str:
231
  """Extract patient's mother's maiden name from extensions."""
232
  patient = self._get_current_patient()
233
+ mothers_maiden = patient.xpath("fhir:extension[@url='http://hl7.org/fhir/StructureDefinition/patient-mothersMaidenName']/fhir:valueString/@value", namespaces=self.ns)
234
+ return mothers_maiden[0] if mothers_maiden else ""
 
 
235
 
236
  def get_birth_place(self) -> Dict[str, str]:
237
  """Extract patient's birth place from extensions."""
238
  patient = self._get_current_patient()
239
+ birth_place = patient.xpath("fhir:extension[@url='http://hl7.org/fhir/StructureDefinition/patient-birthPlace']/fhir:valueAddress", namespaces=self.ns)
240
+ if birth_place:
241
+ city = birth_place[0].xpath("fhir:city/@value", namespaces=self.ns)
242
+ state = birth_place[0].xpath("fhir:state/@value", namespaces=self.ns)
243
+ country = birth_place[0].xpath("fhir:country/@value", namespaces=self.ns)
244
+ return {
245
+ "city": city[0] if city else "",
246
+ "state": state[0] if state else "",
247
+ "country": country[0] if country else ""
248
+ }
249
  return {"city": "", "state": "", "country": ""}
250
 
251
  def get_disability_adjusted_life_years(self) -> Optional[float]:
252
  """Extract disability-adjusted life years from extensions."""
253
  patient = self._get_current_patient()
254
+ daly = patient.xpath("fhir:extension[@url='http://synthetichealth.github.io/synthea/disability-adjusted-life-years']/fhir:valueDecimal/@value", namespaces=self.ns)
255
+ return float(daly[0]) if daly else None
 
 
256
 
257
  def get_quality_adjusted_life_years(self) -> Optional[float]:
258
  """Extract quality-adjusted life years from extensions."""
259
  patient = self._get_current_patient()
260
+ qaly = patient.xpath("fhir:extension[@url='http://synthetichealth.github.io/synthea/quality-adjusted-life-years']/fhir:valueDecimal/@value", namespaces=self.ns)
261
+ return float(qaly[0]) if qaly else None
 
 
262
 
263
  # Marital Status
264
  def get_marital_status(self) -> str:
265
  """Extract patient's marital status."""
266
  patient = self._get_current_patient()
267
+ status = patient.xpath("fhir:maritalStatus/fhir:text/@value", namespaces=self.ns)
268
+ if status:
269
+ return status[0]
270
+ coding = patient.xpath("fhir:maritalStatus/fhir:coding/fhir:display/@value", namespaces=self.ns)
271
+ return coding[0] if coding else ""
272
 
273
  # Communication
274
  def get_language(self) -> str:
275
  """Extract patient's preferred language."""
276
  patient = self._get_current_patient()
277
+ language = patient.xpath("fhir:communication/fhir:language/fhir:text/@value", namespaces=self.ns)
278
+ return language[0] if language else ""
279
 
280
  # Comprehensive Extraction
281
  def get_all_patient_data(self) -> Dict[str, Union[str, Dict, List, float, bool, None]]:
 
361
 
362
  def get_patient_ids(self) -> List[str]:
363
  """Return a list of all patient IDs in the Bundle."""
364
+ return [patient.attrib.get("id", "") for patient in self.patients]
365
 
366
  # # Example usage with integration into app.py
367
  # def integrate_with_app(patient_data: str):