Class: HealthDataStandards::Import::C32::PatientImporter

Inherits:
Object
  • Object
show all
Includes:
HealthDataStandards::Import::CDA::LocatableImportUtils, Util, Singleton
Defined in:
lib/health-data-standards/import/c32/patient_importer.rb

Overview

This class is the central location for taking a HITSP C32 XML document and converting it into the processed form we store in MongoDB. The class does this by running each measure independently on the XML document

This class is a Singleton. It should be accessed by calling PatientImporter.instance

Instance Method Summary collapse

Methods included from HealthDataStandards::Import::CDA::LocatableImportUtils

#import_address, #import_telecom

Constructor Details

#initialize(check_usable = true) ⇒ PatientImporter

Creates a new PatientImporter with the following XPath expressions used to find content in a HITSP C32:

Encounter entries

//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.127']/cda:entry/cda:encounter

Procedure entries

//cda:procedure[cda:templateId/@root='2.16.840.1.113883.10.20.1.29']

Result entries - There seems to be some confusion around the correct templateId, so the code checks for both

//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15.1'] | //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15']

Vital sign entries

//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.14']

Medication entries

//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.112']/cda:entry/cda:substanceAdministration

Codes for medications are found in the substanceAdministration with the following relative XPath

./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code

Condition entries

//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.103']/cda:entry/cda:act/cda:entryRelationship/cda:observation

Codes for conditions are determined by examining the value child element as opposed to the code child element

Social History entries (non-C32 section, specified in the HL7 CCD)

//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.19']

Care Goal entries(non-C32 section, specified in the HL7 CCD)

//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.25']

Allergy entries

//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.18']

Immunization entries

//cda:substanceAdministration[cda:templateId/@root='2.16.840.1.113883.10.20.1.24']

Codes for immunizations are found in the substanceAdministration with the following relative XPath

./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/health-data-standards/import/c32/patient_importer.rb', line 56

def initialize(check_usable = true)
  @section_importers = {}
  @section_importers[:encounters] = CDA::EncounterImporter.new
  @section_importers[:procedures] = CDA::ProcedureImporter.new
  @section_importers[:results] = CDA::ResultImporter.new
  @section_importers[:vital_signs] = CDA::VitalSignImporter.new
  @section_importers[:medications] = CDA::MedicationImporter.new
  @section_importers[:conditions] = ConditionImporter.new
  @section_importers[:social_history] = CDA::SectionImporter.new(CDA::EntryFinder.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.19']"))
  @section_importers[:care_goals] = CareGoalImporter.new
  @section_importers[:medical_equipment] = CDA::MedicalEquipmentImporter.new
  @section_importers[:allergies] = CDA::AllergyImporter.new
  @section_importers[:immunizations] = ImmunizationImporter.new
  @section_importers[:insurance_providers] = InsuranceProviderImporter.new
end

Instance Method Details

#check_for_cause_of_death(c32_patient) ⇒ Object

Checks the conditions to see if any of them have a cause of death set. If they do, it will set the expired field on the Record. This is done here rather than replacing the expried method on Record because other formats may actully tell you whether a patient is dead or not.

Parameters:

  • c32_patient (Record)

    to check the conditions on and set the expired property if applicable



99
100
101
102
103
104
105
# File 'lib/health-data-standards/import/c32/patient_importer.rb', line 99

def check_for_cause_of_death(c32_patient)
  cause_of_death = c32_patient.conditions.detect {|condition| condition.cause_of_death }
  if cause_of_death
    c32_patient.expired = true
    c32_patient.deathdate = cause_of_death.time_of_death
  end
end

#check_usable(check_usable_entries) ⇒ Object

Parameters:

  • value (boolean)

    for check_usable_entries…importer uses true, stats uses false



73
74
75
76
77
# File 'lib/health-data-standards/import/c32/patient_importer.rb', line 73

def check_usable(check_usable_entries)
  @section_importers.each_pair do |section, importer|
    importer.check_for_usable = check_usable_entries
  end
end

#create_c32_hash(record, doc) ⇒ Hash

Create a simple representation of the patient from a HITSP C32

Parameters:

  • record (Record)

    Mongoid model to append the Entry objects to

  • doc (Nokogiri::XML::Document)

    It is expected that the root node of this document will have the “cda” namespace registered to “urn:hl7-org:v3”

Returns:

  • (Hash)

    a represnetation of the patient with symbols as keys for each section



112
113
114
115
116
117
118
# File 'lib/health-data-standards/import/c32/patient_importer.rb', line 112

def create_c32_hash(record, doc)
  nrh = CDA::NarrativeReferenceHandler.new
  nrh.build_id_map(doc)
  @section_importers.each_pair do |section, importer|
    record.send(section.to_setter, importer.create_entries(doc, nrh))
  end
end

#get_demographics(patient, doc) ⇒ Object

Inspects a C32 document and populates the patient Hash with first name, last name birth date, gender and the effectiveTime.

Parameters:

  • patient (Hash)

    A hash that is used to represent the patient

  • doc (Nokogiri::XML::Node)

    The C32 document parsed by Nokogiri



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/health-data-standards/import/c32/patient_importer.rb', line 125

def get_demographics(patient, doc)
  effective_date = doc.at_xpath('/cda:ClinicalDocument/cda:effectiveTime')['value']
  patient.effective_time = HL7Helper.timestamp_to_integer(effective_date)
  patient_role_element = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole')
  patient_element = patient_role_element.at_xpath('./cda:patient')
  patient.title = patient_element.at_xpath('cda:name/cda:title').try(:text)
  patient.first = patient_element.at_xpath('cda:name/cda:given').text
  patient.last = patient_element.at_xpath('cda:name/cda:family').text
  birthdate_in_hl7ts_node = patient_element.at_xpath('cda:birthTime')
  birthdate_in_hl7ts = birthdate_in_hl7ts_node['value']
  patient.birthdate = HL7Helper.timestamp_to_integer(birthdate_in_hl7ts)

  gender_node = patient_element.at_xpath('cda:administrativeGenderCode')
  patient.gender = gender_node['code']
  id_node = patient_role_element.at_xpath('./cda:id')
  patient.medical_record_number = id_node['extension']
  
  # parse race, ethnicity, and spoken language
  race_node = patient_element.at_xpath('cda:raceCode')
  patient.race = { code: race_node['code'], code_set: 'CDC-RE' } if race_node
  ethnicity_node = patient_element.at_xpath('cda:ethnicGroupCode')
  patient.ethnicity = {code: ethnicity_node['code'], code_set: 'CDC-RE'} if ethnicity_node
  marital_status_node = patient_element.at_xpath("./cda:maritalStatusCode")
  patient.marital_status = {code: marital_status_node['code'], code_set: "HL7 Marital Status"} if marital_status_node
  ra_node = patient_element.at_xpath("./cda:religiousAffiliationCode")
  patient.religious_affiliation = {code: ra_node['code'], code_set: "Religious Affiliation"} if ra_node
  languages = patient_element.search('languageCommunication').map {|lc| lc.at_xpath('cda:languageCode')['code'] }
  patient.languages = languages unless languages.empty?
  
  patient.addresses = patient_role_element.xpath("./cda:addr").map { |addr| import_address(addr) }
  patient.telecoms = patient_role_element.xpath("./cda:telecom").map { |tele| import_telecom(tele) }
  
end

#parse_c32(doc) ⇒ Record

Parses a HITSP C32 document and returns a Hash of of the patient.

Parameters:

  • doc (Nokogiri::XML::Document)

    It is expected that the root node of this document will have the “cda” namespace registered to “urn:hl7-org:v3”

Returns:

  • (Record)

    a Mongoid model representing the patient



84
85
86
87
88
89
90
91
# File 'lib/health-data-standards/import/c32/patient_importer.rb', line 84

def parse_c32(doc)
  c32_patient = Record.new
  get_demographics(c32_patient, doc)
  create_c32_hash(c32_patient, doc)
  check_for_cause_of_death(c32_patient)
  
  c32_patient
end