health-data-standards 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/Gemfile +5 -2
  2. data/Rakefile +6 -1
  3. data/VERSION +1 -1
  4. data/lib/health-data-standards.rb +27 -2
  5. data/lib/health-data-standards/export/view_helper.rb +15 -16
  6. data/lib/health-data-standards/ext/string.rb +5 -0
  7. data/lib/health-data-standards/ext/symbol.rb +8 -0
  8. data/lib/health-data-standards/import/c32/allergy_importer.rb +42 -0
  9. data/lib/health-data-standards/import/c32/encounter_importer.rb +80 -0
  10. data/lib/health-data-standards/import/c32/immunization_importer.rb +61 -0
  11. data/lib/health-data-standards/import/c32/medication_importer.rb +138 -0
  12. data/lib/health-data-standards/import/c32/patient_importer.rb +139 -0
  13. data/lib/health-data-standards/import/c32/procedure_importer.rb +55 -0
  14. data/lib/health-data-standards/import/c32/result_importer.rb +58 -0
  15. data/lib/health-data-standards/import/c32/section_importer.rb +214 -0
  16. data/lib/health-data-standards/import/c32/vital_sign_importer.rb +12 -0
  17. data/lib/health-data-standards/models/allergy.rb +4 -0
  18. data/lib/health-data-standards/models/encounter.rb +7 -0
  19. data/lib/health-data-standards/models/entry.rb +131 -3
  20. data/lib/health-data-standards/models/fulfillment_history.rb +11 -0
  21. data/lib/health-data-standards/models/immunization.rb +5 -0
  22. data/lib/health-data-standards/models/lab_result.rb +4 -0
  23. data/lib/health-data-standards/models/medication.rb +25 -0
  24. data/lib/health-data-standards/models/order_information.rb +9 -0
  25. data/lib/health-data-standards/models/procedure.rb +4 -0
  26. data/lib/health-data-standards/models/record.rb +1 -0
  27. data/lib/health-data-standards/util/code_system_helper.rb +41 -0
  28. data/lib/health-data-standards/util/hl7_helper.rb +25 -0
  29. data/templates/_allergies.c32.erb +3 -1
  30. data/templates/_care_goals.c32.erb +1 -1
  31. data/templates/_code_with_reference.c32.erb +10 -5
  32. data/templates/_conditions.c32.erb +2 -2
  33. data/templates/_encounters.c32.erb +2 -1
  34. data/templates/_immunizations.c32.erb +2 -1
  35. data/templates/_medical_equipment.c32.erb +1 -1
  36. data/templates/_medications.c32.erb +2 -1
  37. data/templates/_narrative_block.c32.erb +14 -0
  38. data/templates/_procedures.c32.erb +2 -1
  39. data/templates/_results.c32.erb +2 -2
  40. data/templates/_social_history.c32.erb +1 -1
  41. data/templates/_vital_signs.c32.erb +2 -2
  42. metadata +37 -16
data/Gemfile CHANGED
@@ -2,5 +2,8 @@ source "http://rubygems.org"
2
2
 
3
3
  gemspec :development_group => :test
4
4
 
5
- gem 'rake'
6
- gem 'pry'
5
+ group :development do
6
+ gem 'rake'
7
+ gem 'pry'
8
+ gem 'cover_me'
9
+ end
data/Rakefile CHANGED
@@ -1,7 +1,12 @@
1
1
  require 'rake/testtask'
2
2
 
3
- Rake::TestTask.new do |t|
3
+ Rake::TestTask.new(:test_unit) do |t|
4
4
  t.libs << "test"
5
5
  t.test_files = FileList['test/**/*_test.rb']
6
6
  t.verbose = true
7
+ end
8
+
9
+ task :test => [:test_unit] do
10
+ require 'cover_me'
11
+ CoverMe.complete!
7
12
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.5.0
@@ -2,9 +2,16 @@ require 'erubis'
2
2
  require 'active_support'
3
3
  require 'mongoid'
4
4
  require 'uuid'
5
- require 'quality-measure-engine'
6
5
  require 'builder'
7
6
  require 'csv'
7
+ require 'nokogiri'
8
+
9
+ # Freedom patches
10
+ require_relative 'health-data-standards/ext/symbol'
11
+ require_relative 'health-data-standards/ext/string'
12
+
13
+ require_relative 'health-data-standards/util/hl7_helper'
14
+ require_relative 'health-data-standards/util/code_system_helper'
8
15
 
9
16
  require_relative 'health-data-standards/export/template_helper'
10
17
  require_relative 'health-data-standards/export/view_helper'
@@ -14,4 +21,22 @@ require_relative 'health-data-standards/export/ccr'
14
21
  require_relative 'health-data-standards/export/csv'
15
22
 
16
23
  require_relative 'health-data-standards/models/entry'
17
- require_relative 'health-data-standards/models/record'
24
+ require_relative 'health-data-standards/models/allergy'
25
+ require_relative 'health-data-standards/models/encounter'
26
+ require_relative 'health-data-standards/models/immunization'
27
+ require_relative 'health-data-standards/models/fulfillment_history'
28
+ require_relative 'health-data-standards/models/order_information'
29
+ require_relative 'health-data-standards/models/medication'
30
+ require_relative 'health-data-standards/models/procedure'
31
+ require_relative 'health-data-standards/models/lab_result'
32
+ require_relative 'health-data-standards/models/record'
33
+
34
+ require_relative 'health-data-standards/import/c32/section_importer'
35
+ require_relative 'health-data-standards/import/c32/allergy_importer'
36
+ require_relative 'health-data-standards/import/c32/encounter_importer'
37
+ require_relative 'health-data-standards/import/c32/immunization_importer'
38
+ require_relative 'health-data-standards/import/c32/medication_importer'
39
+ require_relative 'health-data-standards/import/c32/procedure_importer'
40
+ require_relative 'health-data-standards/import/c32/result_importer'
41
+ require_relative 'health-data-standards/import/c32/vital_sign_importer'
42
+ require_relative 'health-data-standards/import/c32/patient_importer'
@@ -1,23 +1,22 @@
1
1
  module HealthDataStandards
2
2
  module Export
3
3
  module ViewHelper
4
- def code_display(entry, tag_name='code', extra_content=nil)
5
- if entry.single_code_value?
6
- code = entry.codes.first[1].first
7
- code_system_oid = QME::Importer::CodeSystemHelper.oid_for_code_system(entry.codes.first[0])
8
- "<#{tag_name} code=\"#{code}\" codeSystem=\"#{code_system_oid}\" #{extra_content}><originalText>#{ERB::Util.html_escape entry.description}</originalText></#{tag_name}>"
4
+ def code_display(entry, options={})
5
+ options['tag_name'] ||= 'code'
6
+ code_string = nil
7
+ preferred_code = entry.preferred_code(options['preferred_code_sets'])
8
+ if preferred_code
9
+ code_system_oid = HealthDataStandards::Util::CodeSystemHelper.oid_for_code_system(preferred_code['code_set'])
10
+ code_string = "<#{options['tag_name']} code=\"#{preferred_code['code']}\" codeSystem=\"#{code_system_oid}\" #{options['extra_content']}>"
9
11
  else
10
- all_codes = []
11
- entry.codes.each_pair {|key, values| values.each {|v| all_codes << {:set => key, :value => v}}}
12
- first_code = all_codes.first
13
- code_string = "<#{tag_name} code=\"#{first_code[:value]}\" codeSystem=\"#{QME::Importer::CodeSystemHelper.oid_for_code_system(first_code[:set])}\">\n"
14
- code_string += "<originalText>#{ERB::Util.html_escape entry.description}</originalText>\n"
15
- all_codes[1..-1].each do |cv|
16
- code_string += "<translation code=\"#{cv[:value]}\" codeSystem=\"#{QME::Importer::CodeSystemHelper.oid_for_code_system(cv[:set])}\"/>\n"
17
- end
18
- code_string += "</#{tag_name}>"
19
- code_string
12
+ code_string = "<#{options['tag_name']} nullFlavor=\"UNK\" #{options['extra_content']}>"
20
13
  end
14
+ code_string += "<originalText>#{ERB::Util.html_escape entry.description}</originalText>"
15
+ entry.translation_codes(options['preferred_code_sets']).each do |translation|
16
+ code_string += "<translation code=\"#{translation['code']}\" codeSystem=\"#{HealthDataStandards::Util::CodeSystemHelper.oid_for_code_system(translation['code_set'])}\"/>\n"
17
+ end
18
+ code_string += "</#{options['tag_name']}>"
19
+ code_string
21
20
  end
22
21
 
23
22
  def status_code_for(entry)
@@ -29,7 +28,7 @@ module HealthDataStandards
29
28
  when 'resolved'
30
29
  '413322009'
31
30
  end
32
- end
31
+ end
33
32
  end
34
33
  end
35
34
  end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def to_boolean
3
+ ['1', 'true', 't'].include?(self.downcase)
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class Symbol
2
+ # Will take the current symbol and append an "=" to the end of it.
3
+ # So :bacon will become :bacon=. It is assumed that this would be
4
+ # passed to Object#send to set the value of something
5
+ def to_setter
6
+ (self.to_s + '=').to_sym
7
+ end
8
+ end
@@ -0,0 +1,42 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module C32
4
+ class AllergyImporter < SectionImporter
5
+
6
+ def initialize
7
+ @entry_xpath = "//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.18']"
8
+ @code_xpath = "./cda:participant/cda:participantRole/cda:playingEntity/cda:code"
9
+ @description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value] "
10
+ @id_map = {}
11
+ end
12
+
13
+ # Traverses that HITSP C32 document passed in using XPath and creates an Array of Entry
14
+ # objects based on what it finds
15
+ # @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
16
+ # will have the "cda" namespace registered to "urn:hl7-org:v3"
17
+ # measure definition
18
+ # @return [Array] will be a list of Entry objects
19
+ def create_entries(doc,id_map = {})
20
+ @id_map = id_map
21
+ allergy_list = []
22
+ entry_elements = doc.xpath(@entry_xpath)
23
+ entry_elements.each do |entry_element|
24
+ allergy = Allergy.new
25
+ extract_codes(entry_element, allergy)
26
+ extract_dates(entry_element, allergy)
27
+ extract_description(entry_element, allergy, id_map)
28
+
29
+ allergy.reaction = extract_code(entry_element,
30
+ "./cda:entryRelationship[@typeCode='MFST']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.54']/cda:value")
31
+
32
+ allergy.severity = extract_code(entry_element,
33
+ "./cda:entryRelationship[@typeCode='MFST']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.54']/cda:entryRelationship[@typeCode='SUBJ']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.55']/cda:value")
34
+
35
+ allergy_list << allergy
36
+ end
37
+ allergy_list
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,80 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module C32
4
+ # TODO Extract Discharge Disposition
5
+ class EncounterImporter < SectionImporter
6
+
7
+ def initialize
8
+ @entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.127']/cda:entry/cda:encounter"
9
+ @code_xpath = "./cda:code"
10
+ @status_xpath = "./cda:statusCode"
11
+ @description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value] "
12
+ @check_for_usable = true # Pilot tools will set this to false
13
+ @id_map = {}
14
+ end
15
+
16
+ # Traverses that HITSP C32 document passed in using XPath and creates an Array of Entry
17
+ # objects based on what it finds
18
+ # @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
19
+ # will have the "cda" namespace registered to "urn:hl7-org:v3"
20
+ # measure definition
21
+ # @return [Array] will be a list of Entry objects
22
+ def create_entries(doc,id_map = {})
23
+ encounter_list = []
24
+ entry_elements = doc.xpath(@entry_xpath)
25
+ entry_elements.each do |entry_element|
26
+ encounter = Encounter.new
27
+ extract_codes(entry_element, encounter)
28
+ extract_dates(entry_element, encounter)
29
+ extract_description(entry_element, encounter, id_map)
30
+ if @check_for_usable
31
+ encounter_list << encounter if encounter.usable?
32
+ else
33
+ encounter_list << encounter
34
+ end
35
+ extract_performer(entry_element, encounter)
36
+ extract_facility(entry_element, encounter)
37
+ extract_reason(entry_element, encounter, id_map)
38
+ extract_admission(entry_element, encounter)
39
+ end
40
+ encounter_list
41
+ end
42
+
43
+ private
44
+
45
+ def extract_performer(parent_element, encounter)
46
+ performer_element = parent_element.at_xpath("./cda:performer")
47
+ encounter.performer = import_actor(performer_element) if performer_element
48
+ end
49
+
50
+ def extract_facility(parent_element, encounter)
51
+ participant_element = parent_element.at_xpath("./cda:participant[@typeCode='LOC']/cda:participantRole[@classCode='SDLOC']")
52
+ encounter.facility = {}
53
+ if (participant_element)
54
+ encounter.facility['organizationName'] = participant_element.at_xpath("./cda:playingEntity/cda:name").try(:text)
55
+ addresses = participant_element.xpath("./cda:addr").try(:map) {|ae| import_address(ae)}
56
+ encounter.facility['addresses'] = addresses
57
+ telecoms = participant_element.xpath("./cda:telecom").try(:map) {|te| import_telecom(te)}
58
+ encounter.facility['telcoms'] = telecoms
59
+ end
60
+ end
61
+
62
+ def extract_reason(parent_element, encounter, id_map)
63
+ reason_element = parent_element.at_xpath("./cda:entryRelationship[@typeCode='RSON']/cda:act")
64
+ if reason_element
65
+ reason = Entry.new
66
+ extract_codes(reason_element, reason)
67
+ extract_description(reason_element, reason, id_map)
68
+ extract_status(reason_element, reason)
69
+ extract_dates(reason_element, reason)
70
+ encounter.reason = reason
71
+ end
72
+ end
73
+
74
+ def extract_admission(parent_element, encounter)
75
+ encounter.admit_type = extract_code(parent_element, "./cda:priorityCode")
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,61 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module C32
4
+ class ImmunizationImporter < SectionImporter
5
+
6
+ def initialize
7
+ @entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.117']/cda:entry/cda:substanceAdministration"
8
+ @code_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code"
9
+ @description_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]"
10
+ @refusal_resason_xpath = "./cda:entryRelationship[@typeCode='RSON']/cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.1.27']/cda:code"
11
+ @check_for_usable = true # Pilot tools will set this to false
12
+ end
13
+
14
+ # Traverses that HITSP C32 document passed in using XPath and creates an Array of Entry
15
+ # objects based on what it finds
16
+ # @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
17
+ # will have the "cda" namespace registered to "urn:hl7-org:v3"
18
+ # measure definition
19
+ # @return [Array] will be a list of Entry objects
20
+ def create_entries(doc,id_map = {})
21
+ immunization_list = []
22
+ entry_elements = doc.xpath(@entry_xpath)
23
+ entry_elements.each do |entry_element|
24
+ immunization = Immunization.new
25
+ extract_codes(entry_element, immunization)
26
+ extract_dates(entry_element, immunization)
27
+ extract_description(entry_element, immunization, id_map)
28
+ extract_refusal(entry_element, immunization)
29
+ extract_performer(entry_element, immunization)
30
+ if @check_for_usable
31
+ immunization_list << immunization if immunization.usable?
32
+ else
33
+ immunization_list << immunization
34
+ end
35
+ end
36
+ immunization_list
37
+ end
38
+
39
+ private
40
+ def extract_refusal(parent_element, immunization)
41
+ negation_indicator = parent_element['negationInd']
42
+ unless negation_indicator.nil?
43
+ immunization.refusal_ind = negation_indicator.eql?('true')
44
+ if immunization.refusal_ind
45
+ refusal_reason_element = parent_element.at_xpath(@refusal_resason_xpath)
46
+ if refusal_reason_element
47
+ immunization.refusal_reason = {'code' => refusal_reason_element['code'],
48
+ 'codeSystem' => 'HL7 No Immunization Reason'}
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def extract_performer(parent_element, immunization)
55
+ performer_element = parent_element.at_xpath("./cda:performer")
56
+ immunization.performer = import_actor(performer_element) if performer_element
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,138 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module C32
4
+
5
+ # TODO: Coded Product Name, Free Text Product Name, Coded Brand Name and Free Text Brand name need to be pulled out separatelty
6
+ # This would mean overriding extract_codes
7
+ # TODO: Patient Instructions needs to be implemented. Will likely be a reference to the narrative section
8
+ # TODO: Couldn't find an example medication reaction. Isn't clear to me how it should be implemented from the specs, so
9
+ # reaction is not implemented.
10
+ # TODO: Couldn't find an example dose indicator. Isn't clear to me how it should be implemented from the specs, so
11
+ # dose indicator is not implemented.
12
+ # TODO: Fill Status is not implemented. Couldn't figure out which entryRelationship it should be nested in
13
+ class MedicationImporter < SectionImporter
14
+
15
+ def initialize
16
+ @entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.112']/cda:entry/cda:substanceAdministration"
17
+ @code_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code"
18
+ @description_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]"
19
+
20
+ @check_for_usable = true # Pilot tools will set this to false
21
+ end
22
+
23
+ # Traverses that HITSP C32 document passed in using XPath and creates an Array of Entry
24
+ # objects based on what it finds
25
+ # @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
26
+ # will have the "cda" namespace registered to "urn:hl7-org:v3"
27
+ # measure definition
28
+ # @return [Array] will be a list of Entry objects
29
+ def create_entries(doc,id_map = {})
30
+ medication_list = []
31
+ entry_elements = doc.xpath(@entry_xpath)
32
+ entry_elements.each do |entry_element|
33
+ medication = Medication.new
34
+ extract_codes(entry_element, medication)
35
+ extract_dates(entry_element, medication)
36
+ extract_description(entry_element, medication, id_map)
37
+
38
+ if medication.description.present?
39
+ medication.free_text_sig = medication.description
40
+ end
41
+
42
+ extract_administration_timing(entry_element, medication)
43
+
44
+ medication.route = extract_code(entry_element, "./cda:routeCode")
45
+ medication.dose = extract_scalar(entry_element, "./cda:doseQuantity")
46
+ medication.site = extract_code(entry_element, "./cda:approachSiteCode", 'SNOMED-CT')
47
+
48
+ extract_dose_restriction(entry_element, medication)
49
+
50
+ medication.product_form = extract_code(entry_element, "./cda:administrationUnitCode", 'NCI Thesaurus')
51
+ medication.delivery_method = extract_code(entry_element, "./cda:code", 'SNOMED-CT')
52
+ medication.type_of_medication = extract_code(entry_element,
53
+ "./cda:entryRelationship[@typeCode='SUBJ']/cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.8.1']/cda:code", 'SNOMED-CT')
54
+ medication.indication = extract_code(entry_element,
55
+ "./cda:entryRelationship[@typeCode='RSON']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.28']/cda:code", 'SNOMED-CT')
56
+ medication.vehicle = extract_code(entry_element,
57
+ "cda:participant/cda:participantRole[cda:code/@code='412307009' and cda:code/@codeSystem='2.16.840.1.113883.6.96']/cda:playingEntity/cda:code", 'SNOMED-CT')
58
+
59
+ extract_order_information(entry_element, medication)
60
+
61
+ extract_fulfillment_history(entry_element, medication)
62
+
63
+ if @check_for_usable
64
+ medication_list << medication if medication.usable?
65
+ else
66
+ medication_list << medication_list
67
+ end
68
+ end
69
+ medication_list
70
+ end
71
+
72
+ private
73
+
74
+ def extract_fulfillment_history(parent_element, medication)
75
+ fhs = parent_element.xpath("./cda:entryRelationship/cda:supply[@moodCode='EVN']")
76
+ if fhs
77
+ fhs.each do |fh_element|
78
+ fulfillment_history = FulfillmentHistory.new
79
+ fulfillment_history.prescription_number = fh_element.at_xpath('./cda:id').try(:[], 'root')
80
+ actor_element = fh_element.at_xpath('./cda:performer')
81
+ if actor_element
82
+ fulfillment_history.provider = import_actor(actor_element)
83
+ addr_element = actor_element.at_xpath("./cda:assignedEntity/cda:addr")
84
+ if addr_element
85
+ fulfillment_history.dispensing_pharmacy_location = import_address(addr_element)
86
+ end
87
+ end
88
+ hl7_timestamp = fh_element.at_xpath('./cda:effectiveTime').try(:[], 'value')
89
+ fulfillment_history.dispense_date = HL7Helper.timestamp_to_integer(hl7_timestamp) if hl7_timestamp
90
+ fulfillment_history.quantity_dispensed = extract_scalar(fh_element, "./cda:quantity")
91
+ fulfillment_history.fill_number = fh_element.at_xpath("./cda:entryRelationship[@typeCode='COMP']/cda:sequenceNumber").try(:[], 'value').to_i
92
+ medication.fulfillmentHistory << fulfillment_history
93
+ end
94
+ end
95
+ end
96
+
97
+ def extract_order_information(parent_element, medication)
98
+ order_elements = parent_element.xpath("./cda:entryRelationship[@typeCode='REFR']/cda:supply[@moodCode='INT']")
99
+ if order_elements
100
+ order_elements.each do |order_element|
101
+ order_information = OrderInformation.new
102
+
103
+ order_information.order_number = order_element.at_xpath('./cda:id').try(:[], 'root')
104
+ order_information.fills = order_element.at_xpath('./cda:repeatNumber').try(:[], 'value').try(:to_i)
105
+ order_information.quantity_ordered = extract_scalar(order_element, "./cda:quantity")
106
+
107
+ medication.orderInformation << order_information
108
+ end
109
+ end
110
+ end
111
+
112
+ def extract_administration_timing(parent_element, medication)
113
+ administration_timing_element = parent_element.at_xpath("./cda:effectiveTime[2]")
114
+ if administration_timing_element
115
+ at = {}
116
+ if administration_timing_element['institutionSpecified']
117
+ at['institutionSpecified'] = administration_timing_element['institutionSpecified'].to_boolean
118
+ end
119
+ at['period'] = extract_scalar(administration_timing_element, "./cda:period")
120
+ if at.present?
121
+ medication.administration_timing = at
122
+ end
123
+ end
124
+ end
125
+
126
+ def extract_dose_restriction(parent_element, medication)
127
+ dre = parent_element.at_xpath("./cda:maxDoseQuantity")
128
+ if dre
129
+ dr = {}
130
+ dr['numerator'] = extract_scalar(dre, "./cda:numerator")
131
+ dr['denominator'] = extract_scalar(dre, "./cda:denominator")
132
+ medication.dose_restriction = dr
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end