hqmf-parser 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +23 -0
- data/README.md +903 -0
- data/Rakefile +19 -0
- data/VERSION +1 -0
- data/lib/hqmf-generator/hqmf-generator.rb +308 -0
- data/lib/hqmf-model/attribute.rb +35 -0
- data/lib/hqmf-model/data_criteria.rb +322 -0
- data/lib/hqmf-model/document.rb +172 -0
- data/lib/hqmf-model/population_criteria.rb +90 -0
- data/lib/hqmf-model/precondition.rb +85 -0
- data/lib/hqmf-model/types.rb +318 -0
- data/lib/hqmf-model/utilities.rb +52 -0
- data/lib/hqmf-parser.rb +54 -0
- data/lib/hqmf-parser/1.0/attribute.rb +68 -0
- data/lib/hqmf-parser/1.0/comparison.rb +34 -0
- data/lib/hqmf-parser/1.0/data_criteria.rb +105 -0
- data/lib/hqmf-parser/1.0/document.rb +209 -0
- data/lib/hqmf-parser/1.0/expression.rb +52 -0
- data/lib/hqmf-parser/1.0/population_criteria.rb +79 -0
- data/lib/hqmf-parser/1.0/precondition.rb +89 -0
- data/lib/hqmf-parser/1.0/range.rb +65 -0
- data/lib/hqmf-parser/1.0/restriction.rb +157 -0
- data/lib/hqmf-parser/1.0/utilities.rb +41 -0
- data/lib/hqmf-parser/2.0/data_criteria.rb +319 -0
- data/lib/hqmf-parser/2.0/document.rb +165 -0
- data/lib/hqmf-parser/2.0/population_criteria.rb +53 -0
- data/lib/hqmf-parser/2.0/precondition.rb +44 -0
- data/lib/hqmf-parser/2.0/types.rb +223 -0
- data/lib/hqmf-parser/2.0/utilities.rb +30 -0
- data/lib/hqmf-parser/converter/pass1/data_criteria_converter.rb +254 -0
- data/lib/hqmf-parser/converter/pass1/document_converter.rb +183 -0
- data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +135 -0
- data/lib/hqmf-parser/converter/pass1/precondition_converter.rb +164 -0
- data/lib/hqmf-parser/converter/pass1/precondition_extractor.rb +159 -0
- data/lib/hqmf-parser/converter/pass1/simple_data_criteria.rb +35 -0
- data/lib/hqmf-parser/converter/pass1/simple_operator.rb +89 -0
- data/lib/hqmf-parser/converter/pass1/simple_population_criteria.rb +10 -0
- data/lib/hqmf-parser/converter/pass1/simple_precondition.rb +63 -0
- data/lib/hqmf-parser/converter/pass1/simple_restriction.rb +64 -0
- data/lib/hqmf-parser/converter/pass2/comparison_converter.rb +91 -0
- data/lib/hqmf-parser/converter/pass2/operator_converter.rb +169 -0
- data/lib/hqmf-parser/converter/pass3/specific_occurrence_converter.rb +86 -0
- data/lib/hqmf-parser/converter/pass3/specific_occurrence_converter_bak.rb +70 -0
- data/lib/hqmf-parser/parser.rb +22 -0
- data/lib/hqmf-parser/value_sets/value_set_parser.rb +206 -0
- data/lib/tasks/coverme.rake +8 -0
- data/lib/tasks/hqmf.rake +141 -0
- data/lib/tasks/value_sets.rake +23 -0
- metadata +159 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
|
2
|
+
module HQMF
|
3
|
+
module Conversion
|
4
|
+
module Utilities
|
5
|
+
def build_hash(source, elements)
|
6
|
+
hash = {}
|
7
|
+
elements.each do |element|
|
8
|
+
value = source.send(element)
|
9
|
+
hash[element] = value unless value.nil?
|
10
|
+
end
|
11
|
+
hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def json_array(elements)
|
15
|
+
return nil if elements.nil?
|
16
|
+
array = []
|
17
|
+
elements.each do |element|
|
18
|
+
if (element.is_a? OpenStruct)
|
19
|
+
array << openstruct_to_json(element)
|
20
|
+
else
|
21
|
+
array << element.to_json
|
22
|
+
end
|
23
|
+
end
|
24
|
+
array.compact!
|
25
|
+
(array.empty?) ? nil : array
|
26
|
+
end
|
27
|
+
|
28
|
+
def openstruct_to_json(element)
|
29
|
+
json = {}
|
30
|
+
element.marshal_dump.each do |key,value|
|
31
|
+
if value.is_a? OpenStruct
|
32
|
+
json[key] = openstruct_to_json(value)
|
33
|
+
elsif (value.class.to_s.split("::").first.start_with? 'HQMF')
|
34
|
+
json[key] = value.to_json
|
35
|
+
else
|
36
|
+
json[key] = value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
json
|
40
|
+
end
|
41
|
+
|
42
|
+
def check_equality(left,right)
|
43
|
+
same = true
|
44
|
+
left.instance_variables.each do |variable|
|
45
|
+
same &&= left.instance_variable_get(variable) == right.instance_variable_get(variable)
|
46
|
+
end
|
47
|
+
same
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/hqmf-parser.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# require
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'pry'
|
4
|
+
require 'json'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'health-data-standards'
|
7
|
+
|
8
|
+
# require_relative
|
9
|
+
require_relative 'hqmf-model/utilities.rb'
|
10
|
+
|
11
|
+
require_relative 'hqmf-parser/1.0/utilities'
|
12
|
+
require_relative 'hqmf-parser/1.0/range'
|
13
|
+
require_relative 'hqmf-parser/1.0/document'
|
14
|
+
require_relative 'hqmf-parser/1.0/data_criteria'
|
15
|
+
require_relative 'hqmf-parser/1.0/attribute'
|
16
|
+
require_relative 'hqmf-parser/1.0/population_criteria'
|
17
|
+
require_relative 'hqmf-parser/1.0/precondition'
|
18
|
+
require_relative 'hqmf-parser/1.0/restriction'
|
19
|
+
require_relative 'hqmf-parser/1.0/comparison'
|
20
|
+
require_relative 'hqmf-parser/1.0/expression'
|
21
|
+
|
22
|
+
require_relative 'hqmf-parser/2.0/utilities'
|
23
|
+
require_relative 'hqmf-parser/2.0/types'
|
24
|
+
require_relative 'hqmf-parser/2.0/document'
|
25
|
+
require_relative 'hqmf-parser/2.0/data_criteria'
|
26
|
+
require_relative 'hqmf-parser/2.0/population_criteria'
|
27
|
+
require_relative 'hqmf-parser/2.0/precondition'
|
28
|
+
|
29
|
+
require_relative 'hqmf-model/data_criteria.rb'
|
30
|
+
require_relative 'hqmf-model/document.rb'
|
31
|
+
require_relative 'hqmf-model/population_criteria.rb'
|
32
|
+
require_relative 'hqmf-model/precondition.rb'
|
33
|
+
require_relative 'hqmf-model/types.rb'
|
34
|
+
require_relative 'hqmf-model/attribute.rb'
|
35
|
+
|
36
|
+
require_relative 'hqmf-parser/converter/pass1/document_converter'
|
37
|
+
require_relative 'hqmf-parser/converter/pass1/data_criteria_converter'
|
38
|
+
require_relative 'hqmf-parser/converter/pass1/population_criteria_converter'
|
39
|
+
require_relative 'hqmf-parser/converter/pass1/precondition_converter'
|
40
|
+
require_relative 'hqmf-parser/converter/pass1/precondition_extractor'
|
41
|
+
require_relative 'hqmf-parser/converter/pass1/simple_restriction'
|
42
|
+
require_relative 'hqmf-parser/converter/pass1/simple_operator'
|
43
|
+
require_relative 'hqmf-parser/converter/pass1/simple_precondition'
|
44
|
+
require_relative 'hqmf-parser/converter/pass1/simple_data_criteria'
|
45
|
+
require_relative 'hqmf-parser/converter/pass1/simple_population_criteria'
|
46
|
+
|
47
|
+
require_relative 'hqmf-parser/converter/pass2/comparison_converter'
|
48
|
+
require_relative 'hqmf-parser/converter/pass2/operator_converter'
|
49
|
+
|
50
|
+
require_relative 'hqmf-parser/value_sets/value_set_parser'
|
51
|
+
|
52
|
+
require_relative 'hqmf-parser/parser'
|
53
|
+
|
54
|
+
require_relative 'hqmf-generator/hqmf-generator'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module HQMF1
|
2
|
+
# Represents a HQMF measure attribute
|
3
|
+
class Attribute
|
4
|
+
|
5
|
+
include HQMF1::Utilities
|
6
|
+
|
7
|
+
# Create a new instance based on the supplied HQMF
|
8
|
+
# @param [Nokogiri::XML::Element] entry the measure attribute element
|
9
|
+
def initialize(entry)
|
10
|
+
@entry = entry
|
11
|
+
end
|
12
|
+
|
13
|
+
# Get the attribute code
|
14
|
+
# @return [String] the code
|
15
|
+
def code
|
16
|
+
if (@entry.at_xpath('./cda:code/@code'))
|
17
|
+
@entry.at_xpath('./cda:code/@code').value
|
18
|
+
elsif @entry.at_xpath('./cda:code/@nullFlavor')
|
19
|
+
@entry.at_xpath('./cda:code/@nullFlavor').value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get the attribute name
|
24
|
+
# @return [String] the name
|
25
|
+
def name
|
26
|
+
if (@entry.at_xpath('./cda:code/@displayName'))
|
27
|
+
@entry.at_xpath('./cda:code/@displayName').value
|
28
|
+
elsif @entry.at_xpath('cda:code/cda:originalText')
|
29
|
+
@entry.at_xpath('cda:code/cda:originalText').text
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the attribute id, used elsewhere in the document to refer to the attribute
|
34
|
+
# @return [String] the id
|
35
|
+
def id
|
36
|
+
attr_val('./cda:id/@root')
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get the attribute value
|
40
|
+
# @return [String] the value
|
41
|
+
def value
|
42
|
+
val = attr_val('./cda:value/@value')
|
43
|
+
val ||= attr_val('./cda:value/@extension')
|
44
|
+
if val
|
45
|
+
val
|
46
|
+
else
|
47
|
+
@entry.at_xpath('./cda:value').inner_text
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get the unit of the attribute value or nil if none is defined
|
52
|
+
# @return [String] the unit
|
53
|
+
def unit
|
54
|
+
attr_val('./cda:value/@unit')
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get a JS friendly constant name for this measure attribute
|
58
|
+
def const_name
|
59
|
+
components = name.gsub(/\W/,' ').split.collect {|word| word.strip.upcase }
|
60
|
+
components.join '_'
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_json
|
64
|
+
{self.const_name => build_hash(self, [:code,:value,:unit,:name,:id])}
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module HQMF1
|
2
|
+
class Comparison
|
3
|
+
|
4
|
+
include HQMF1::Utilities
|
5
|
+
|
6
|
+
attr_reader :restrictions, :data_criteria_id, :title, :subset
|
7
|
+
|
8
|
+
def initialize(data_criteria_id, entry, parent, doc)
|
9
|
+
@doc = doc
|
10
|
+
@data_criteria_id = data_criteria_id
|
11
|
+
@entry = entry
|
12
|
+
title_def = @entry.at_xpath('./*/cda:title')
|
13
|
+
if title_def
|
14
|
+
@title = title_def.inner_text
|
15
|
+
end
|
16
|
+
@restrictions = []
|
17
|
+
restriction_def = @entry.at_xpath('./*/cda:sourceOf')
|
18
|
+
if restriction_def
|
19
|
+
@entry.xpath('./*/cda:sourceOf').each do |restriction|
|
20
|
+
@restrictions << Restriction.new(restriction, self, @doc)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_json
|
26
|
+
|
27
|
+
json = build_hash(self, [:data_criteria_id,:title,:subset])
|
28
|
+
json[:restrictions] = json_array(@restrictions)
|
29
|
+
json
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module HQMF1
|
2
|
+
# Represents a data criteria specification
|
3
|
+
class DataCriteria
|
4
|
+
|
5
|
+
include HQMF1::Utilities
|
6
|
+
|
7
|
+
attr_accessor :code_list_id, :derived_from, :definition, :status, :negation, :specific_occurrence, :specific_occurrence_const
|
8
|
+
|
9
|
+
# Create a new instance based on the supplied HQMF entry
|
10
|
+
# @param [Nokogiri::XML::Element] entry the parsed HQMF entry
|
11
|
+
def initialize(entry)
|
12
|
+
@entry = entry
|
13
|
+
|
14
|
+
template_map = HQMF::DataCriteria.get_template_id_map()
|
15
|
+
oid_xpath_file = File.expand_path('../data_criteria_oid_xpath.json', __FILE__)
|
16
|
+
oid_xpath_map = JSON.parse(File.read(oid_xpath_file))
|
17
|
+
template_id = attr_val('cda:act/cda:templateId/@root') || attr_val('cda:observation/cda:templateId/@root')
|
18
|
+
|
19
|
+
# check to see if this is a derived data criteria. These are used for multiple occurrences.
|
20
|
+
derived_entry = @entry.at_xpath('./*/cda:sourceOf[@typeCode="DRIV"]')
|
21
|
+
if derived_entry
|
22
|
+
derived = derived_entry.at_xpath('cda:act/cda:id/@root') || derived_entry.at_xpath('cda:observation/cda:id/@root')
|
23
|
+
@derived_from = derived.value
|
24
|
+
@@occurrences[@derived_from] ||= Counter.new
|
25
|
+
@occurrence_key = @@occurrences[@derived_from].next
|
26
|
+
@specific_occurrence = "#{('A'..'ZZ').to_a[@occurrence_key]}"
|
27
|
+
end
|
28
|
+
|
29
|
+
template = template_map[template_id]
|
30
|
+
if template
|
31
|
+
@negation=template["negation"]
|
32
|
+
@definition=template["definition"]
|
33
|
+
@status=template["status"]
|
34
|
+
@key=@definition+(@status.empty? ? '' : "_#{@status}")
|
35
|
+
else
|
36
|
+
raise "Unknown data criteria template identifier [#{template_id}]"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get the code list OID of the criteria, used as an index to the code list database
|
40
|
+
@code_list_id = attr_val(oid_xpath_map[@key]['oid_xpath'])
|
41
|
+
unless @code_list_id
|
42
|
+
puts "\tcode list id not found, getting default" if !@derived_from
|
43
|
+
@code_list_id = attr_val('cda:act/cda:sourceOf//cda:code/@code')
|
44
|
+
end
|
45
|
+
|
46
|
+
puts "\tno oid defined for data criteria: #{@key}" if !@code_list_id and !@derived_from
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get the identifier of the criteria, used elsewhere within the document for referencing
|
51
|
+
# @return [String] the identifier of this data criteria
|
52
|
+
def id
|
53
|
+
attr_val('cda:act/cda:id/@root') || attr_val('cda:observation/cda:id/@root')
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get the title of the criteria, provides a human readable description
|
57
|
+
# @return [String] the title of this data criteria
|
58
|
+
def title
|
59
|
+
title = description
|
60
|
+
title = "Occurrence #{@specific_occurrence}: #{title}" if @derived_from
|
61
|
+
title
|
62
|
+
end
|
63
|
+
|
64
|
+
def description
|
65
|
+
if (@entry.at_xpath('.//cda:title'))
|
66
|
+
description = @entry.at_xpath('.//cda:title').inner_text
|
67
|
+
else
|
68
|
+
description = @entry.at_xpath('.//cda:localVariableName').inner_text
|
69
|
+
end
|
70
|
+
description
|
71
|
+
end
|
72
|
+
|
73
|
+
# Get a JS friendly constant name for this measure attribute
|
74
|
+
def const_name
|
75
|
+
components = title.gsub(/\W/,' ').split.collect {|word| word.strip.upcase }
|
76
|
+
if @derived_from
|
77
|
+
components << @@id.next
|
78
|
+
@specific_occurrence_const = (description.gsub(/\W/,' ').split.collect {|word| word.strip.upcase }).join '_'
|
79
|
+
end
|
80
|
+
components.join '_'
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_json
|
84
|
+
json = build_hash(self, [:id,:title,:code_list_id,:derived_from,:description, :definition, :status, :negation, :specific_occurrence,:specific_occurrence_const])
|
85
|
+
{
|
86
|
+
self.const_name => json
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
# Simple class to issue monotonically increasing integer identifiers
|
91
|
+
class Counter
|
92
|
+
def initialize
|
93
|
+
@count = -1
|
94
|
+
end
|
95
|
+
|
96
|
+
def next
|
97
|
+
@count+=1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
@@id = Counter.new
|
101
|
+
@@occurrences = {}
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module HQMF1
|
2
|
+
# Class representing an HQMF document
|
3
|
+
class Document
|
4
|
+
|
5
|
+
include HQMF1::Utilities
|
6
|
+
|
7
|
+
attr_reader :hqmf_id, :hqmf_set_id, :hqmf_version_number
|
8
|
+
|
9
|
+
# Create a new HQMF1::Document instance by parsing the supplied contents
|
10
|
+
# @param [String] hqmf_contents the contents of an HQMF v1.0 document
|
11
|
+
def initialize(hqmf_contents)
|
12
|
+
@doc = Document.parse(hqmf_contents)
|
13
|
+
@data_criteria = @doc.xpath('//cda:section[cda:code/@code="57025-9"]/cda:entry').collect do |entry|
|
14
|
+
DataCriteria.new(entry)
|
15
|
+
end
|
16
|
+
|
17
|
+
backfill_derived_code_lists
|
18
|
+
|
19
|
+
@attributes = @doc.xpath('//cda:subjectOf/cda:measureAttribute').collect do |attr|
|
20
|
+
Attribute.new(attr)
|
21
|
+
end
|
22
|
+
@population_criteria = @doc.xpath('//cda:section[cda:code/@code="57026-7"]/cda:entry').collect do |attr|
|
23
|
+
PopulationCriteria.new(attr, self)
|
24
|
+
end
|
25
|
+
|
26
|
+
@stratification = @doc.xpath('//cda:section[cda:code/@code="69669-0"]/cda:entry').collect do |attr|
|
27
|
+
PopulationCriteria.new(attr, self)
|
28
|
+
end
|
29
|
+
|
30
|
+
if (@stratification and !@stratification.empty?)
|
31
|
+
initial_populations = @population_criteria.select {|pc| pc.code.starts_with? 'IPP'}
|
32
|
+
initial_populations.each do |population|
|
33
|
+
|
34
|
+
@stratification.each do |stratification|
|
35
|
+
new_population = HQMF1::PopulationCriteria.new(population.entry, population.doc)
|
36
|
+
new_population.hqmf_id = new_population.id
|
37
|
+
new_population.stratification_id = stratification.id
|
38
|
+
new_population.id = "#{new_population.id}_#{stratification.id}"
|
39
|
+
ids = stratification.preconditions.map(&:id)
|
40
|
+
new_population.preconditions.delete_if {|precondition| ids.include? precondition.id}
|
41
|
+
new_population.preconditions.concat(stratification.preconditions)
|
42
|
+
new_population.preconditions.rotate!(-1*stratification.preconditions.size)
|
43
|
+
@population_criteria << new_population
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
@hqmf_set_id = @doc.at_xpath('//cda:setId/@root').value.upcase
|
51
|
+
@hqmf_id = @doc.at_xpath('//cda:id/@root').value.upcase
|
52
|
+
@hqmf_version_number = @doc.at_xpath('//cda:versionNumber/@value').value.to_i
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
# Get the title of the measure
|
57
|
+
# @return [String] the title
|
58
|
+
def title
|
59
|
+
@doc.at_xpath('cda:QualityMeasureDocument/cda:title').inner_text
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get the description of the measure
|
63
|
+
# @return [String] the description
|
64
|
+
def description
|
65
|
+
@doc.at_xpath('cda:QualityMeasureDocument/cda:text').inner_text
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get all the attributes defined by the measure
|
69
|
+
# @return [Array] an array of HQMF1::Attribute
|
70
|
+
def all_attributes
|
71
|
+
@attributes
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get a specific attribute by id.
|
75
|
+
# @param [String] id the attribute identifier
|
76
|
+
# @return [HQMF1::Attribute] the matching attribute, raises an Exception if not found
|
77
|
+
def attribute(id)
|
78
|
+
find(@attributes, :id, id)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Get a specific attribute by code.
|
82
|
+
# @param [String] code the attribute code
|
83
|
+
# @return [HQMF1::Attribute] the matching attribute, raises an Exception if not found
|
84
|
+
def attribute_for_code(code)
|
85
|
+
find(@attributes, :code, code)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get all the population criteria defined by the measure
|
89
|
+
# @return [Array] an array of HQMF1::PopulationCriteria
|
90
|
+
def all_population_criteria
|
91
|
+
@population_criteria
|
92
|
+
end
|
93
|
+
|
94
|
+
def stratification
|
95
|
+
@stratification
|
96
|
+
end
|
97
|
+
|
98
|
+
# Get a specific population criteria by id.
|
99
|
+
# @param [String] id the population identifier
|
100
|
+
# @return [HQMF1::PopulationCriteria] the matching criteria, raises an Exception if not found
|
101
|
+
def population_criteria(id)
|
102
|
+
find(@population_criteria, :id, id)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get a specific population criteria by code.
|
106
|
+
# @param [String] code the population criteria code
|
107
|
+
# @return [HQMF1::PopulationCriteria] the matching criteria, raises an Exception if not found
|
108
|
+
def population_criteria_for_code(code)
|
109
|
+
find(@population_criteria, :code, code)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Get all the data criteria defined by the measure
|
113
|
+
# @return [Array] an array of HQMF1::DataCriteria describing the data elements used by the measure
|
114
|
+
def all_data_criteria
|
115
|
+
@data_criteria
|
116
|
+
end
|
117
|
+
|
118
|
+
# Get a specific data criteria by id.
|
119
|
+
# @param [String] id the data criteria identifier
|
120
|
+
# @return [HQMF1::DataCriteria] the matching data criteria, raises an Exception if not found
|
121
|
+
def data_criteria(id)
|
122
|
+
val = find(@data_criteria, :id, id) || raise("unknown data criteria #{id}")
|
123
|
+
end
|
124
|
+
|
125
|
+
# Parse an XML document from the supplied contents
|
126
|
+
# @return [Nokogiri::XML::Document]
|
127
|
+
def self.parse(hqmf_contents)
|
128
|
+
doc = Nokogiri::XML(hqmf_contents)
|
129
|
+
doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
|
130
|
+
doc
|
131
|
+
end
|
132
|
+
|
133
|
+
# if the data criteria is derived from another criteria, then we want to grab the properties from the derived criteria
|
134
|
+
# this is typically the case with Occurrence A, Occurrence B type data criteria
|
135
|
+
def backfill_derived_code_lists
|
136
|
+
data_criteria_by_id = {}
|
137
|
+
@data_criteria.each {|criteria| data_criteria_by_id[criteria.id] = criteria}
|
138
|
+
@data_criteria.each do |criteria|
|
139
|
+
if (criteria.derived_from)
|
140
|
+
derived_from = data_criteria_by_id[criteria.derived_from]
|
141
|
+
criteria.definition = derived_from.definition
|
142
|
+
criteria.status = derived_from.status
|
143
|
+
criteria.code_list_id = derived_from.code_list_id
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_json
|
149
|
+
json = build_hash(self, [:title, :description, :hqmf_id, :hqmf_set_id, :hqmf_version_number])
|
150
|
+
|
151
|
+
json[:data_criteria] = {}
|
152
|
+
@data_criteria.each do |criteria|
|
153
|
+
criteria_json = criteria.to_json
|
154
|
+
# check if the key already exists... if it does redefine the key
|
155
|
+
if (json[:data_criteria][criteria_json.keys.first])
|
156
|
+
criteria_json = {"#{criteria_json.keys.first}_#{@@ids.next}" => criteria_json.values.first}
|
157
|
+
end
|
158
|
+
json[:data_criteria].merge! criteria_json
|
159
|
+
end
|
160
|
+
|
161
|
+
json[:metadata] = {}
|
162
|
+
json[:attributes] = {}
|
163
|
+
@attributes.each do |attribute|
|
164
|
+
if (attribute.id)
|
165
|
+
json[:attributes].merge! attribute.to_json
|
166
|
+
else
|
167
|
+
json[:metadata].merge! attribute.to_json
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
json[:logic] = {}
|
173
|
+
counters = {}
|
174
|
+
@population_criteria.each do |population|
|
175
|
+
population_json = population.to_json
|
176
|
+
key = population_json.keys.first
|
177
|
+
if json[:logic][key]
|
178
|
+
counters[key] ||= 0
|
179
|
+
counters[key] += 1
|
180
|
+
population_json["#{key}_#{counters[key]}"] = population_json[key]
|
181
|
+
population_json.delete(key)
|
182
|
+
end
|
183
|
+
json[:logic].merge! population_json
|
184
|
+
end
|
185
|
+
|
186
|
+
clean_json_recursive(json)
|
187
|
+
json
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def find(collection, attribute, value)
|
193
|
+
collection.find {|e| e.send(attribute)==value}
|
194
|
+
end
|
195
|
+
|
196
|
+
# Simple class to issue monotonically increasing integer identifiers
|
197
|
+
class Counter
|
198
|
+
def initialize
|
199
|
+
@count = 0
|
200
|
+
end
|
201
|
+
|
202
|
+
def next
|
203
|
+
@count+=1
|
204
|
+
end
|
205
|
+
end
|
206
|
+
@@ids = Counter.new
|
207
|
+
|
208
|
+
end
|
209
|
+
end
|