health-data-standards 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/Gemfile +9 -1
  2. data/Rakefile +14 -4
  3. data/lib/health-data-standards.rb +23 -0
  4. data/lib/health-data-standards/export/ccr.rb +55 -56
  5. data/lib/health-data-standards/export/hdata/metadata.rb +16 -0
  6. data/lib/health-data-standards/export/html.rb +21 -0
  7. data/lib/health-data-standards/export/template_helper.rb +3 -0
  8. data/lib/health-data-standards/export/view_helper.rb +29 -5
  9. data/lib/health-data-standards/import/c32/condition_importer.rb +31 -33
  10. data/lib/health-data-standards/import/c32/encounter_importer.rb +4 -6
  11. data/lib/health-data-standards/import/c32/medication_importer.rb +1 -5
  12. data/lib/health-data-standards/import/c32/organization_importer.rb +23 -0
  13. data/lib/health-data-standards/import/c32/patient_importer.rb +1 -4
  14. data/lib/health-data-standards/import/c32/provider_importer.rb +43 -30
  15. data/lib/health-data-standards/import/c32/section_importer.rb +20 -41
  16. data/lib/health-data-standards/import/ccr/patient_importer.rb +27 -10
  17. data/lib/health-data-standards/import/ccr/provider_importer.rb +29 -41
  18. data/lib/health-data-standards/import/ccr/section_importer.rb +38 -27
  19. data/lib/health-data-standards/import/green_c32/allergy_importer.rb +20 -0
  20. data/lib/health-data-standards/import/green_c32/condition_importer.rb +2 -3
  21. data/lib/health-data-standards/import/green_c32/encounter_importer.rb +42 -0
  22. data/lib/health-data-standards/import/green_c32/immunization_importer.rb +23 -0
  23. data/lib/health-data-standards/import/green_c32/medication_importer.rb +69 -0
  24. data/lib/health-data-standards/import/green_c32/procedure_importer.rb +35 -0
  25. data/lib/health-data-standards/import/green_c32/result_importer.rb +21 -8
  26. data/lib/health-data-standards/import/green_c32/section_importer.rb +55 -9
  27. data/lib/health-data-standards/import/green_c32/social_history_importer.rb +18 -0
  28. data/lib/health-data-standards/import/green_c32/vital_sign_importer.rb +21 -0
  29. data/lib/health-data-standards/import/hdata/metadata_importer.rb +82 -0
  30. data/lib/health-data-standards/import/provider_import_utils.rb +23 -0
  31. data/lib/health-data-standards/models/address.rb +11 -0
  32. data/lib/health-data-standards/models/allergy.rb +1 -0
  33. data/lib/health-data-standards/models/condition.rb +1 -1
  34. data/lib/health-data-standards/models/encounter.rb +11 -6
  35. data/lib/health-data-standards/models/entry.rb +16 -5
  36. data/lib/health-data-standards/models/fulfillment_history.rb +3 -5
  37. data/lib/health-data-standards/models/immunization.rb +7 -1
  38. data/lib/health-data-standards/models/medication.rb +4 -3
  39. data/lib/health-data-standards/models/metadata/author.rb +16 -0
  40. data/lib/health-data-standards/models/metadata/base.rb +20 -0
  41. data/lib/health-data-standards/models/metadata/change_info.rb +9 -0
  42. data/lib/health-data-standards/models/metadata/link_info.rb +9 -0
  43. data/lib/health-data-standards/models/metadata/pedigree.rb +15 -0
  44. data/lib/health-data-standards/models/organization.rb +8 -0
  45. data/lib/health-data-standards/models/procedure.rb +5 -2
  46. data/lib/health-data-standards/models/provider.rb +6 -1
  47. data/lib/health-data-standards/models/record.rb +13 -3
  48. data/lib/health-data-standards/models/social_history.rb +3 -0
  49. data/lib/health-data-standards/models/telecom.rb +9 -0
  50. data/lib/health-data-standards/models/vital_sign.rb +2 -0
  51. data/lib/health-data-standards/util/code_system_helper.rb +3 -1
  52. data/templates/_address.gc32.erb +9 -0
  53. data/templates/_allergies.c32.erb +2 -2
  54. data/templates/_allergy.gc32.erb +13 -0
  55. data/templates/_care_goals.c32.erb +1 -1
  56. data/templates/_condition.gc32.erb +6 -6
  57. data/templates/_conditions.c32.erb +2 -2
  58. data/templates/_encounter.gc32.erb +32 -0
  59. data/templates/_encounters.c32.erb +1 -1
  60. data/templates/_immunization.gc32.erb +9 -0
  61. data/templates/_immunizations.c32.erb +1 -1
  62. data/templates/_medical_equipment.c32.erb +1 -1
  63. data/templates/_medication.gc32.erb +60 -0
  64. data/templates/_medications.c32.erb +1 -1
  65. data/templates/_narrative_block.c32.erb +1 -1
  66. data/templates/_organization.gc32.erb +10 -0
  67. data/templates/_pedigree.hdata.erb +24 -0
  68. data/templates/_procedure.gc32.erb +8 -0
  69. data/templates/_procedures.c32.erb +1 -1
  70. data/templates/_provider.gc32.erb +19 -0
  71. data/templates/_results.c32.erb +1 -1
  72. data/templates/_social_history.c32.erb +1 -1
  73. data/templates/_social_history.gc32.erb +6 -0
  74. data/templates/_telecom.gc32.erb +1 -0
  75. data/templates/_vital_sign.gc32.erb +12 -0
  76. data/templates/_vital_signs.c32.erb +1 -1
  77. data/templates/metadata.hdata.erb +35 -0
  78. data/templates/show.html.erb +287 -0
  79. metadata +50 -15
@@ -0,0 +1,20 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module GreenC32
4
+ class AllergyImporter < SectionImporter
5
+ include Singleton
6
+
7
+ def import(allergy_xml)
8
+ allergy_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
9
+ allergy_element = allergy_xml.xpath("./gc32:allergy")
10
+ allergy = Allergy.new
11
+ extract_entry(allergy_element, allergy)
12
+ allergy.type = extract_node_text(allergy_element.at_xpath("./gc32:type"))
13
+ extract_code(allergy_element, allergy, "./gc32:reaction", :reaction)
14
+ extract_code(allergy_element, allergy, "./gc32:severity", :severity)
15
+ allergy
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -10,16 +10,15 @@ module HealthDataStandards
10
10
 
11
11
  def import(condition_xml)
12
12
  condition_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
13
-
14
13
  condition_element = condition_xml.xpath("./gc32:condition")
15
14
 
16
15
  condition = Condition.new
17
-
16
+
18
17
  extract_entry(condition_element, condition)
19
18
  extract_name(condition_element, condition)
20
- extract_interval(condition_element, condition)
21
19
  extract_cause_of_death(condition_element, condition)
22
20
  extract_type(condition_element, condition)
21
+
23
22
  condition
24
23
  end
25
24
 
@@ -0,0 +1,42 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module GreenC32
4
+ class EncounterImporter < SectionImporter
5
+ include Singleton
6
+
7
+ def initialize
8
+ super
9
+ end
10
+
11
+ def import(encounter_xml)
12
+ encounter = Encounter.new
13
+ encounter_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
14
+ encounter_element = encounter_xml.xpath("/gc32:encounter")
15
+ extract_entry(encounter_element, encounter)
16
+ extract_code(encounter_element, encounter, "./gc32:dischargeDisposition", :discharge_disposition)
17
+ extract_code(encounter_element, encounter, "./gc32:admissionType", :admit_type)
18
+ extract_code(encounter_element, encounter, "./gc32:reasonForVisit", :reason)
19
+ extract_code(encounter_element, encounter)
20
+ extract_facility(encounter_element, encounter)
21
+
22
+ free_text = encounter_element.xpath("./gc32:freeText").first
23
+
24
+ if free_text
25
+ encounter.free_text = free_text.content
26
+ end
27
+
28
+ encounter
29
+ end
30
+
31
+ def extract_facility(encounter_element, encounter)
32
+ facility_element = encounter_element.xpath("./gc32:facility").first
33
+ if facility_element
34
+ organization = extract_organization(facility_element)
35
+ encounter.facility = organization
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module GreenC32
4
+ class ImmunizationImporter < SectionImporter
5
+ include Singleton
6
+
7
+ def import(immunization_xml)
8
+ immunization_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
9
+ immunization_element = immunization_xml.at_xpath("./gc32:immunization")
10
+ immunization = Immunization.new
11
+ extract_entry(immunization_element, immunization)
12
+ extract_time(immunization_element, immunization, "./gc32:administeredDate")
13
+ extract_code(immunization_element, immunization, "./gc32:refusalReason")
14
+ series_number = extract_node_text(immunization_element.at_xpath("./gc32:seriesNumber"))
15
+ immunization.series_number = series_number.to_i if series_number
16
+ immunization.refusalInd = extract_node_attribute(immunization_element, :refused, true)
17
+ immunization
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,69 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module GreenC32
4
+ class MedicationImporter < SectionImporter
5
+ include Singleton
6
+
7
+ def import(med_xml)
8
+ med_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
9
+ med_element = med_xml.at_xpath("./gc32:medication")
10
+ medication = Medication.new
11
+ extract_entry(med_element, medication)
12
+ extract_interval(med_element, medication, "administrationTiming")
13
+ extract_administration_timing(med_element, medication)
14
+ medication.dose = extract_quantity(med_element, "./gc32:dose")
15
+ extract_med_code_attribute(med_element, medication, :type, :typeOfMedication)
16
+ extract_med_code_attribute(med_element, medication, :statusOfMedication)
17
+ extract_med_code_attribute(med_element, medication, :route)
18
+ extract_med_code_attribute(med_element, medication, :site)
19
+ extract_dose_restriction(med_element, medication)
20
+ extract_med_code_attribute(med_element, medication, :indication)
21
+ extract_med_code_attribute(med_element, medication, :productForm)
22
+ extract_med_code_attribute(med_element, medication, :vehicle)
23
+ extract_med_code_attribute(med_element, medication, :reaction)
24
+ extract_med_code_attribute(med_element, medication, :deliveryMethod)
25
+ medication.free_text_sig = extract_node_text(med_element.at_xpath("./gc32:freeTextSig"))
26
+ medication.fulfillment_instructions = extract_node_text(med_element.at_xpath("./gc32:patientInstructions"))
27
+ medication.dose_indicator = extract_node_text(med_element.at_xpath("./gc32:doseIndicator"))
28
+ medication.fulfillment_history = extract_fulfillment_history(med_element)
29
+ medication.order_information = extract_order_information(med_element)
30
+ medication
31
+ end
32
+
33
+ def extract_administration_timing(element,entry)
34
+ entry.administration_timing = {"period" => extract_quantity(element, "./gc32:administrationTiming/gc32:period"),
35
+ "institutionSpecified" => extract_node_attribute(element.at_xpath("./gc32:administrationTiming"), :institutionSpecified)}
36
+ end
37
+
38
+ def extract_dose_restriction(element, entry)
39
+ dose_element = element.at_xpath("./gc32:doseRestriction")
40
+ entry.dose_restriction = {"numerator" => extract_quantity(dose_element, "./gc32:numerator"), "denominator" => extract_quantity(dose_element,"./gc32:denominator")}
41
+ end
42
+
43
+ def extract_fulfillment_history(med_element)
44
+ med_element.xpath("./gc32:fulfillmentHistory").map do |fh_doc|
45
+ fh = FulfillmentHistory.new(quantityDispensed: extract_quantity(fh_doc, "./gc32:quantityDispensed"))
46
+ fh.prescription_number = extract_node_text(fh_doc.at_xpath("./gc32:prescriptionUmber"))
47
+ extract_time(fh_doc, fh, "./gc32:dispenseDate", :dispense_date)
48
+ fh
49
+ end
50
+ end
51
+
52
+ def extract_order_information(med_element)
53
+ med_element.xpath("./gc32:orderInformation").map do |oi_doc|
54
+ oi = OrderInformation.new(fills: extract_node_attribute(oi_doc, :fills, true), orderNumber: extract_node_attribute(oi_doc, :orderNumber))
55
+ extract_time(oi_doc, oi, "./gc32:orderDateTime", :order_date_time)
56
+ extract_time(oi_doc, oi, "./gc32:expiresDateTime", :order_expiration_date_time)
57
+ oi
58
+ end
59
+ end
60
+
61
+ def extract_med_code_attribute(doc, med, attribute, mongo_attribute_name=nil)
62
+ mongo_attribute_name ||= attribute
63
+ extract_code(doc, med, "./gc32:#{attribute}", mongo_attribute_name)
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,35 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module GreenC32
4
+ class ProcedureImporter < SectionImporter
5
+
6
+ include Singleton
7
+
8
+ def initialize
9
+ super
10
+ end
11
+
12
+ def import(procedure_xml)
13
+ procedure_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
14
+
15
+ procedure_element = procedure_xml.xpath("./gc32:procedure")
16
+
17
+ procedure = Procedure.new
18
+
19
+ extract_entry(procedure_element, procedure)
20
+ extract_type(procedure_element, procedure)
21
+
22
+ procedure
23
+ end
24
+
25
+ private
26
+
27
+ def extract_type(procedure_xml, procedure)
28
+ type = procedure_xml.xpath("./gc32:type").first
29
+ procedure.type = extract_node_text(type)
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end
@@ -2,28 +2,41 @@ module HealthDataStandards
2
2
  module Import
3
3
  module GreenC32
4
4
  class ResultImporter < SectionImporter
5
+
5
6
  include Singleton
6
7
 
8
+ #-------------------------------------------------------------------------------
9
+
7
10
  def initialize
8
11
  super
9
12
  @range = "./gc32:referenceRange"
10
13
  @interpretation = "./gc32:interpretation"
14
+ @klass = LabResult
15
+ @base_xpath = "./gc32:result"
11
16
  end
12
17
 
13
- def import(result)
14
- result.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
18
+ #-------------------------------------------------------------------------------
19
+
20
+ def import(result_xml)
21
+ result_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
15
22
 
16
- result_element = result.xpath("./gc32:result")
17
- lab_result = LabResult.new(reference_range: extract_node_text(result_element.xpath(@range)))
23
+ result_element = result_xml.xpath(@base_xpath)
24
+ lab_result = @klass.new(reference_range: extract_node_text(result_element.xpath(@range)))
18
25
 
19
- extract_entry(result_element, lab_result)
20
- extract_time(result_element, lab_result)
21
- extract_value(result_element, lab_result)
22
- extract_code(result_element, lab_result, @interpretation, :interpretation)
26
+ extract_result(result_element, lab_result)
23
27
 
24
28
  lab_result
25
29
  end
26
30
 
31
+ #-------------------------------------------------------------------------------
32
+ private
33
+ #-------------------------------------------------------------------------------
34
+
35
+ def extract_result(result_element, lab_result)
36
+ extract_entry(result_element, lab_result)
37
+ extract_code(result_element, lab_result, @interpretation, :interpretation)
38
+ end
39
+
27
40
  end
28
41
  end
29
42
  end
@@ -37,36 +37,82 @@ module HealthDataStandards
37
37
  entry.status = status
38
38
  end
39
39
 
40
+ def extract_effective_time(element, entry)
41
+ if element.at_xpath("./gc32:effectiveTime/gc32:start")
42
+ extract_interval(element,entry)
43
+ else
44
+ extract_time(element, entry)
45
+ end
46
+ end
47
+
40
48
  def extract_time(element, entry, xpath = "./gc32:effectiveTime", attribute = "time")
41
- datetime = element.xpath(xpath).first
49
+ datetime = element.at_xpath(xpath)
42
50
  return unless datetime && !datetime.inner_text.empty?
43
51
  entry.send("#{attribute}=", Time.parse(datetime.inner_text).to_i)
44
52
  end
45
53
 
46
- def extract_interval(element, entry)
47
- extract_time(element, entry, "./gc32:effectiveTime/gc32:start", "start_time")
48
- extract_time(element, entry, "./gc32:effectiveTime/gc32:end", "end_time")
54
+ def extract_interval(element, entry, element_name="effectiveTime")
55
+ extract_time(element, entry, "./gc32:#{element_name}/gc32:start", "start_time")
56
+ extract_time(element, entry, "./gc32:#{element_name}/gc32:end", "end_time")
49
57
  end
50
58
 
51
- def extract_value(element, entry)
52
-
53
- value_element = element.xpath(@value).first
59
+ def extract_quantity(element, xpath)
60
+ value_element = element.at_xpath(xpath)
54
61
 
55
62
  return unless value_element
56
63
 
57
64
  node_value = extract_node_attribute(value_element, "amount", true)
58
65
  node_units = extract_node_attribute(value_element, "unit")
59
66
 
60
- entry.value = {'scalar' => node_value, "unit" => node_units} if node_value
61
-
67
+ return {} unless node_value
68
+
69
+ {'scalar' => node_value, "unit" => node_units}
70
+ end
71
+
72
+ def extract_value(element, entry)
73
+ entry.value = extract_quantity(element, @value)
62
74
  end
63
75
 
64
76
  def extract_entry(element, entry)
65
77
  extract_code(element, entry)
66
78
  extract_description(element, entry)
67
79
  extract_status(element, entry)
80
+ extract_value(element, entry)
81
+ extract_effective_time(element, entry)
68
82
  end
69
83
 
84
+ def extract_organization(organization_element)
85
+ org_id = extract_node_text(organization_element.xpath("./gc32:id"))
86
+ organization = org_id ? Organization.find_or_create_by(id: org_id) : Organization.new
87
+ if organization.new_record?
88
+ else
89
+ organization.name = extract_node_text(organization_element.xpath("./gc32:name"))
90
+ organization.addresses = organization_element.xpath("./gc32:address").map { |addr| extract_address(addr) }
91
+ organization.telecoms = organization_element.xpath("./gc32:telecom").map { |tele| extract_telecom(tele) }
92
+ organization.save!
93
+ end
94
+
95
+ return organization
96
+ end
97
+
98
+ def extract_address(address_element)
99
+ address = Address.new
100
+ address.street = address_element.xpath("./gc32:street").map { |st| extract_node_text(st) }
101
+ address.city = extract_node_text(address_element.xpath("./gc32:city"))
102
+ address.state = extract_node_text(address_element.xpath("./gc32:state"))
103
+ address.zip = extract_node_text(address_element.xpath("./gc32:postalCode"))
104
+ address
105
+ end
106
+
107
+ def extract_telecom(telecom_element)
108
+ telecom = Telecom.new
109
+ telecom.use = extract_node_attribute(telecom_element, :type)
110
+ telecom.value = extract_node_attribute(telecom_element, :value)
111
+ telecom.preferred = extract_node_attribute(telecom_element, :preferred)
112
+ telecom
113
+ end
114
+
115
+
70
116
  private
71
117
 
72
118
  def build_code(code_element)
@@ -0,0 +1,18 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module GreenC32
4
+ class SocialHistoryImporter < SectionImporter
5
+ include Singleton
6
+
7
+ def import(sh_xml)
8
+ sh_xml.root.add_namespace_definition('gc32', "urn:hl7-org:greencda:c32")
9
+ sh_element = sh_xml.at_xpath("./gc32:socialHistory")
10
+ sh = SocialHistory.new
11
+ extract_entry(sh_element, sh)
12
+ extract_code(sh_element, sh, "./gc32:type", :type)
13
+ sh
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module GreenC32
4
+ # This really needs to get refactored to share code with result importer
5
+ class VitalSignImporter < ResultImporter
6
+
7
+ include Singleton
8
+
9
+ #-------------------------------------------------------------------------------
10
+
11
+ def initialize
12
+ super
13
+ @range = "./gc32:referenceRange"
14
+ @klass = VitalSign
15
+ @base_xpath = "./gc32:vitalSign"
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,82 @@
1
+ module HealthDataStandards
2
+ module Import
3
+ module Hdata
4
+ class MetadataImporter
5
+ include Singleton
6
+
7
+ def import(meta_xml)
8
+ meta_xml.root.add_namespace_definition("hrf-md", Metadata::NS)
9
+ meta_element = meta_xml.at_xpath("./hrf-md:DocumentMetadata")
10
+ return unless meta_element
11
+
12
+ meta = Metadata::Base.new
13
+
14
+ extract_metadata(meta_element, meta)
15
+
16
+ meta
17
+ end
18
+
19
+ def extract_metadata(meta_element, meta)
20
+ meta.mime_types = meta_element.xpath("./hrf-md:MediaType").map { |media| media.text }
21
+ meta.confidentiality = meta_element.at_xpath("./hrf-md:Confidentiality").try(:text)
22
+ meta.pedigrees = meta_element.xpath("./hrf-md:PedigreeInfo").map { |ped| extract_pedigree(ped) }
23
+ creation_el = meta_element.at_xpath("./hrf-md:RecordDate/hrf-md:CreatedDateTime")
24
+ meta.original_creation_time = Time.parse(creation_el.text) if creation_el
25
+ meta.linked_documents = meta_element.xpath("./hrf-md:LinkedDocuments/hrf-md:Link").map {|l| extract_link_info(l)}
26
+ copied_elements = meta_element.xpath("./hrf-md:RecordDate/hrf-md:Copied/hrf-md:CopiedInfo")
27
+ meta.copied_dates = copied_elements.map { |cp| extract_change_info(cp) }
28
+ modified_elements = meta_element.xpath("./hrf-md:RecordDate/hrf-md:Modified/hrf-md:ModifiedInfo")
29
+ meta.modified_dates = modified_elements.map { |md| extract_change_info(md) }
30
+ meta
31
+ end
32
+
33
+ def extract_pedigree(pedi_el)
34
+ return unless pedi_el
35
+
36
+ author = extract_author(pedi_el)
37
+ organization = pedi_el.at_xpath("./hrf-md:Organization")
38
+
39
+ ped = Metadata::Pedigree.new(author: author,
40
+ organization: organization.try(:content))
41
+
42
+ source_pedigree_els = pedi_el.xpath("./hrf-md:Source/hrf-md:PedigreeInfo")
43
+ ped.source_pedigrees = source_pedigree_els.map { |ped_el| extract_pedigree(ped_el) }
44
+ ped.derived = pedi_el.attribute("derived")# == "true" ? true : false
45
+ # ped.signature = pedi_el.at_xpath("./hrf-md:Signature/")
46
+
47
+ source_doc_els = pedi_el.xpath("./hrf-md:Source/hrf-md:Document")
48
+ ped.source_documents = source_doc_els.map { |doc_el| extract_link_info(doc_el) }
49
+
50
+ ped
51
+ end
52
+
53
+ def extract_author(pedi_el)
54
+ return unless pedi_el
55
+ author = pedi_el.at_xpath("./hrf-md:Author")
56
+ return unless author
57
+ Metadata::Author.new(name: author.try(:content),
58
+ type: author.attribute('typeCode').try("content"),
59
+ role: author.attribute('role').try("content"))
60
+ end
61
+
62
+ def extract_link_info(link_info_el)
63
+ return unless link_info_el
64
+ target_el = link_info_el.at_xpath("./hrf-md:Target")
65
+ return unless target_el
66
+ Metadata::LinkInfo.new(uri: target_el.content,
67
+ extension: target_el.attribute("TargetExtension").try(:content))
68
+ end
69
+
70
+ def extract_change_info(change_info_el)
71
+ return unless change_info_el
72
+ change_info = Metadata::ChangeInfo.new
73
+ change_info.timestamp = change_info_el.at_xpath("./hrf-md:ChangeDateTime").try("content")
74
+ change_info.pedigree = extract_pedigree(change_info_el.at_xpath("./hrf-md:PedigreeInfo"))
75
+ change_info_el
76
+ change_info
77
+ end
78
+
79
+ end
80
+ end
81
+ end
82
+ end