health-data-standards 0.7.1 → 0.8.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 (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