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,53 @@
|
|
1
|
+
module HQMF2
|
2
|
+
# Represents an HQMF population criteria, also supports all the same methods as
|
3
|
+
# HQMF2::Precondition
|
4
|
+
class PopulationCriteria
|
5
|
+
|
6
|
+
include HQMF2::Utilities
|
7
|
+
|
8
|
+
attr_reader :preconditions, :id, :hqmf_id, :title, :type
|
9
|
+
|
10
|
+
# Create a new population criteria from the supplied HQMF entry
|
11
|
+
# @param [Nokogiri::XML::Element] the HQMF entry
|
12
|
+
def initialize(entry, doc)
|
13
|
+
@doc = doc
|
14
|
+
@entry = entry
|
15
|
+
@hqmf_id = attr_val('./*/cda:id/@extension')
|
16
|
+
@title = attr_val('./*/cda:code/cda:displayName/@value')
|
17
|
+
@type = attr_val('./*/cda:code/@code')
|
18
|
+
@preconditions = @entry.xpath('./*/cda:precondition[not(@nullFlavor)]', HQMF2::Document::NAMESPACES).collect do |precondition|
|
19
|
+
Precondition.new(precondition, @doc)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_human_readable_id(id)
|
24
|
+
@id = id
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return true of this precondition represents a conjunction with nested preconditions
|
28
|
+
# or false of this precondition is a reference to a data criteria
|
29
|
+
def conjunction?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the conjunction code, e.g. allTrue, allFalse
|
34
|
+
# @return [String] conjunction code
|
35
|
+
def conjunction_code
|
36
|
+
case @type
|
37
|
+
when HQMF::PopulationCriteria::IPP, HQMF::PopulationCriteria::DENOM, HQMF::PopulationCriteria::NUMER
|
38
|
+
HQMF::Precondition::ALL_TRUE
|
39
|
+
when HQMF::PopulationCriteria::EXCEP, HQMF::PopulationCriteria::DENEX
|
40
|
+
HQMF::Precondition::AT_LEAST_ONE_TRUE
|
41
|
+
else
|
42
|
+
raise "Unknown population type [#{@type}]"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_model
|
47
|
+
mps = preconditions.collect {|p| p.to_model}
|
48
|
+
HQMF::PopulationCriteria.new(id, hqmf_id, type, mps, title)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module HQMF2
|
2
|
+
|
3
|
+
class Precondition
|
4
|
+
|
5
|
+
include HQMF2::Utilities
|
6
|
+
|
7
|
+
attr_reader :preconditions, :reference
|
8
|
+
|
9
|
+
def initialize(entry, doc)
|
10
|
+
@doc = doc
|
11
|
+
@entry = entry
|
12
|
+
@preconditions = @entry.xpath('./*/cda:precondition', HQMF2::Document::NAMESPACES).collect do |precondition|
|
13
|
+
Precondition.new(precondition, @doc)
|
14
|
+
end
|
15
|
+
reference_def = @entry.at_xpath('./*/cda:id', HQMF2::Document::NAMESPACES)
|
16
|
+
if reference_def
|
17
|
+
@reference = Reference.new(reference_def)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Return true of this precondition represents a conjunction with nested preconditions
|
22
|
+
# or false of this precondition is a reference to a data criteria
|
23
|
+
def conjunction?
|
24
|
+
@preconditions.length>0
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get the conjunction code, e.g. allTrue, allFalse
|
28
|
+
# @return [String] conjunction code
|
29
|
+
def conjunction_code
|
30
|
+
if conjunction?
|
31
|
+
@entry.at_xpath('./*[1]', HQMF2::Document::NAMESPACES).name
|
32
|
+
else
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_model
|
38
|
+
pcs = preconditions.collect {|p| p.to_model}
|
39
|
+
mr = reference ? reference.to_model : nil
|
40
|
+
HQMF::Precondition.new(nil, pcs, mr, conjunction_code, false)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
module HQMF2
|
2
|
+
# Used to represent 'any value' in criteria that require a value be present but
|
3
|
+
# don't specify any restrictions on that value
|
4
|
+
class AnyValue
|
5
|
+
attr_reader :type
|
6
|
+
|
7
|
+
def initialize(type='ANYNonNull')
|
8
|
+
@type = type
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_model
|
12
|
+
HQMF::AnyValue.new(@type)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Represents a bound within a HQMF pauseQuantity, has a value, a unit and an
|
17
|
+
# inclusive/exclusive indicator
|
18
|
+
class Value
|
19
|
+
include HQMF2::Utilities
|
20
|
+
|
21
|
+
attr_reader :type, :unit, :value
|
22
|
+
|
23
|
+
def initialize(entry, default_type='PQ')
|
24
|
+
@entry = entry
|
25
|
+
@type = attr_val('./@xsi:type') || default_type
|
26
|
+
@unit = attr_val('./@unit')
|
27
|
+
@value = attr_val('./@value')
|
28
|
+
end
|
29
|
+
|
30
|
+
def inclusive?
|
31
|
+
case attr_val('./@inclusive')
|
32
|
+
when 'false'
|
33
|
+
false
|
34
|
+
else
|
35
|
+
true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def derived?
|
40
|
+
case attr_val('./@nullFlavor')
|
41
|
+
when 'DER'
|
42
|
+
true
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def expression
|
49
|
+
if !derived?
|
50
|
+
nil
|
51
|
+
else
|
52
|
+
attr_val('./cda:expression/@value')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_model
|
57
|
+
HQMF::Value.new(type,unit,value,inclusive?,derived?,expression)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Represents a HQMF physical quantity which can have low and high bounds
|
62
|
+
class Range
|
63
|
+
include HQMF2::Utilities
|
64
|
+
attr_accessor :low, :high, :width
|
65
|
+
|
66
|
+
def initialize(entry, type=nil)
|
67
|
+
@type = type
|
68
|
+
@entry = entry
|
69
|
+
if @entry
|
70
|
+
@low = optional_value('./cda:low', default_bounds_type)
|
71
|
+
@high = optional_value('./cda:high', default_bounds_type)
|
72
|
+
@width = optional_value('./cda:width', 'PQ')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def type
|
77
|
+
@type || attr_val('./@xsi:type')
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_model
|
81
|
+
lm = low ? low.to_model : nil
|
82
|
+
hm = high ? high.to_model : nil
|
83
|
+
wm = width ? width.to_model : nil
|
84
|
+
HQMF::Range.new(type, lm, hm, wm)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def optional_value(xpath, type)
|
90
|
+
value_def = @entry.at_xpath(xpath, HQMF2::Document::NAMESPACES)
|
91
|
+
if value_def
|
92
|
+
Value.new(value_def, type)
|
93
|
+
else
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def default_bounds_type
|
99
|
+
case type
|
100
|
+
when 'IVL_TS'
|
101
|
+
'TS'
|
102
|
+
else
|
103
|
+
'PQ'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Represents a HQMF effective time which is a specialization of a interval
|
109
|
+
class EffectiveTime < Range
|
110
|
+
def initialize(entry)
|
111
|
+
super
|
112
|
+
end
|
113
|
+
|
114
|
+
def type
|
115
|
+
'IVL_TS'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Represents a HQMF CD value which has a code and codeSystem
|
120
|
+
class Coded
|
121
|
+
include HQMF2::Utilities
|
122
|
+
|
123
|
+
def initialize(entry)
|
124
|
+
@entry = entry
|
125
|
+
end
|
126
|
+
|
127
|
+
def type
|
128
|
+
attr_val('./@xsi:type') || 'CD'
|
129
|
+
end
|
130
|
+
|
131
|
+
def system
|
132
|
+
attr_val('./@codeSystem')
|
133
|
+
end
|
134
|
+
|
135
|
+
def code
|
136
|
+
attr_val('./@code')
|
137
|
+
end
|
138
|
+
|
139
|
+
def code_list_id
|
140
|
+
attr_val('./@valueSet')
|
141
|
+
end
|
142
|
+
|
143
|
+
def title
|
144
|
+
attr_val('./@displayName')
|
145
|
+
end
|
146
|
+
|
147
|
+
def value
|
148
|
+
code
|
149
|
+
end
|
150
|
+
|
151
|
+
def derived?
|
152
|
+
false
|
153
|
+
end
|
154
|
+
|
155
|
+
def unit
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
|
159
|
+
def to_model
|
160
|
+
HQMF::Coded.new(type, system, code, code_list_id, title)
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
class SubsetOperator
|
166
|
+
include HQMF2::Utilities
|
167
|
+
|
168
|
+
attr_reader :type, :value
|
169
|
+
|
170
|
+
def initialize(entry)
|
171
|
+
@entry = entry
|
172
|
+
@type = attr_val('./cda:subsetCode/@code')
|
173
|
+
value_def = @entry.at_xpath('./*/cda:repeatNumber', HQMF2::Document::NAMESPACES)
|
174
|
+
if value_def
|
175
|
+
@value = HQMF2::Range.new(value_def, 'IVL_INT')
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def to_model
|
180
|
+
vm = value ? value.to_model : nil
|
181
|
+
HQMF::SubsetOperator.new(type, vm)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class TemporalReference
|
186
|
+
include HQMF2::Utilities
|
187
|
+
|
188
|
+
attr_reader :type, :reference, :range
|
189
|
+
|
190
|
+
def initialize(entry)
|
191
|
+
@entry = entry
|
192
|
+
@type = attr_val('./@typeCode')
|
193
|
+
@reference = Reference.new(@entry.at_xpath('./*/cda:id', HQMF2::Document::NAMESPACES))
|
194
|
+
range_def = @entry.at_xpath('./cda:pauseQuantity', HQMF2::Document::NAMESPACES)
|
195
|
+
if range_def
|
196
|
+
@range = HQMF2::Range.new(range_def, 'IVL_PQ')
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def to_model
|
201
|
+
rm = range ? range.to_model : nil
|
202
|
+
HQMF::TemporalReference.new(type, reference.to_model, rm)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Represents a HQMF reference from a precondition to a data criteria
|
207
|
+
class Reference
|
208
|
+
include HQMF2::Utilities
|
209
|
+
|
210
|
+
def initialize(entry)
|
211
|
+
@entry = entry
|
212
|
+
end
|
213
|
+
|
214
|
+
def id
|
215
|
+
attr_val('./@extension')
|
216
|
+
end
|
217
|
+
|
218
|
+
def to_model
|
219
|
+
HQMF::Reference.new(id)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module HQMF2
|
2
|
+
module Utilities
|
3
|
+
|
4
|
+
include HQMF::Conversion::Utilities
|
5
|
+
|
6
|
+
# Utility function to handle optional attributes
|
7
|
+
# @param xpath an XPath that identifies an XML attribute
|
8
|
+
# @return the value of the attribute or nil if the attribute is missing
|
9
|
+
def attr_val(xpath)
|
10
|
+
Utilities::attr_val(@entry, xpath)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Utility function to handle optional attributes
|
14
|
+
# @param xpath an XPath that identifies an XML attribute
|
15
|
+
# @return the value of the attribute or nil if the attribute is missing
|
16
|
+
def self.attr_val(node, xpath)
|
17
|
+
attr = node.at_xpath(xpath, HQMF2::Document::NAMESPACES)
|
18
|
+
if attr
|
19
|
+
attr.value
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_xml
|
26
|
+
@entry.to_xml
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
module HQMF
|
2
|
+
# Class representing an HQMF document
|
3
|
+
class DataCriteriaConverter
|
4
|
+
|
5
|
+
attr_reader :v1_data_criteria_by_id, :v2_data_criteria, :v2_data_criteria_to_delete, :measure_period_criteria, :measure_period_v1_keys, :specific_occurrences
|
6
|
+
|
7
|
+
def initialize(doc, measure_period)
|
8
|
+
@doc = doc
|
9
|
+
@v1_data_criteria_by_id = {}
|
10
|
+
@v2_data_criteria = []
|
11
|
+
@v2_data_criteria_to_delete = {}
|
12
|
+
@specific_occurrences = {}
|
13
|
+
@measure_period = measure_period
|
14
|
+
parse()
|
15
|
+
end
|
16
|
+
|
17
|
+
def final_v2_data_criteria
|
18
|
+
@v2_data_criteria.delete_if {|criteria| @v2_data_criteria_to_delete[criteria.id] }
|
19
|
+
end
|
20
|
+
|
21
|
+
# duplicates a data criteria. This is important because we may be modifying source data criteria like patient characteristic birthdate to add restrictions
|
22
|
+
# the restrictions added may be different for the numerator, denominator, different IPP_1, IPP_2, etc.
|
23
|
+
def duplicate_data_criteria(data_criteria, parent_id)
|
24
|
+
|
25
|
+
# if this is a specific occurrence, then we do not want to duplicate it.
|
26
|
+
# we may need to duplicate it for a population however.
|
27
|
+
# return data_criteria if (specific_occurrences[data_criteria.id])
|
28
|
+
|
29
|
+
if (data_criteria.is_a? HQMF::Converter::SimpleDataCriteria and data_criteria.precondition_id == parent_id)
|
30
|
+
new_data_criteria = data_criteria
|
31
|
+
else
|
32
|
+
new_data_criteria = HQMF::Converter::SimpleDataCriteria.from_data_criteria(data_criteria)
|
33
|
+
new_data_criteria.assign_precondition(parent_id)
|
34
|
+
@v2_data_criteria << new_data_criteria
|
35
|
+
# we want to delete the original for data criteria that have been duplicated
|
36
|
+
@v2_data_criteria_to_delete[data_criteria.id] = true if !@v2_data_criteria_to_delete.keys.include? data_criteria.id
|
37
|
+
end
|
38
|
+
|
39
|
+
new_data_criteria
|
40
|
+
end
|
41
|
+
|
42
|
+
# make sure that if a data criteria is used as a target, that it is not deleted by someone else.
|
43
|
+
# this is required for birthdate in NQF0106
|
44
|
+
def validate_not_deleted(target)
|
45
|
+
@v2_data_criteria_to_delete[target] = false
|
46
|
+
end
|
47
|
+
|
48
|
+
# grouping data criteria are used to allow a single reference off of a temporal reference or subset operator
|
49
|
+
# grouping data criteria can reference either regular data criteria as children, or other grouping data criteria
|
50
|
+
def create_group_data_criteria(preconditions, type, value, parent_id, id, standard_category, qds_data_type)
|
51
|
+
extract_group_data_criteria_tree(HQMF::DataCriteria::UNION,preconditions, type, parent_id)
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_group_data_criteria(children, section, parent_id, derivation_operator)
|
55
|
+
|
56
|
+
criteria_ids = children.map(&:id)
|
57
|
+
# make sure nobody else is going to delete the criteria we've grouped
|
58
|
+
criteria_ids.each {|target| validate_not_deleted(target)}
|
59
|
+
|
60
|
+
id = "#{parent_id}_#{section}_#{@@ids.next}"
|
61
|
+
title = "#{id}"
|
62
|
+
description = ""
|
63
|
+
definition = 'derived'
|
64
|
+
_display_name,_code_list_id,_status,_value,_field_values,_effective_time,_inline_code_list,_negation_code_list_id, = nil
|
65
|
+
_negation = false
|
66
|
+
|
67
|
+
group_criteria = HQMF::DataCriteria.new(id, title, _display_name, description, _code_list_id, criteria_ids, derivation_operator, definition, _status,
|
68
|
+
_value, _field_values, _effective_time, _inline_code_list,_negation,_negation_code_list_id,nil,nil,nil,nil)
|
69
|
+
|
70
|
+
@v2_data_criteria << group_criteria
|
71
|
+
|
72
|
+
group_criteria
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
# pull the children data criteria out of a set of preconditions
|
77
|
+
def extract_group_data_criteria_tree(conjunction, preconditions, type, parent_id)
|
78
|
+
|
79
|
+
children = []
|
80
|
+
preconditions.each do |precondition|
|
81
|
+
if (precondition.comparison?)
|
82
|
+
if (precondition.reference.id == HQMF::Document::MEASURE_PERIOD_ID)
|
83
|
+
children << measure_period_criteria
|
84
|
+
else
|
85
|
+
children << v2_data_criteria_by_id[precondition.reference.id]
|
86
|
+
end
|
87
|
+
else
|
88
|
+
converted_conjunction = convert_grouping_conjunction(precondition.conjunction_code)
|
89
|
+
children << extract_group_data_criteria_tree(converted_conjunction, precondition.preconditions, type, parent_id)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# if we have just one child element, just return it. An AND or OR of a single item is not useful.
|
94
|
+
if (children.size > 1)
|
95
|
+
build_group_data_criteria(children, type, parent_id, conjunction)
|
96
|
+
else
|
97
|
+
children.first
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
def convert_grouping_conjunction(conjunction)
|
103
|
+
case conjunction
|
104
|
+
when HQMF::Precondition::AT_LEAST_ONE_TRUE
|
105
|
+
HQMF::DataCriteria::UNION
|
106
|
+
when HQMF::Precondition::ALL_TRUE
|
107
|
+
HQMF::DataCriteria::XPRODUCT
|
108
|
+
else
|
109
|
+
'unknown'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# pull the children data criteria out of a set of preconditions
|
114
|
+
def self.extract_data_criteria(preconditions, data_criteria_converter)
|
115
|
+
flattened = []
|
116
|
+
preconditions.each do |precondition|
|
117
|
+
if (precondition.comparison?)
|
118
|
+
if (precondition.reference.id == HQMF::Document::MEASURE_PERIOD_ID)
|
119
|
+
flattened << data_criteria_converter.measure_period_criteria
|
120
|
+
else
|
121
|
+
flattened << data_criteria_converter.v2_data_criteria_by_id[precondition.reference.id]
|
122
|
+
end
|
123
|
+
else
|
124
|
+
flattened.concat(extract_data_criteria(precondition.preconditions,data_criteria_converter))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
flattened
|
128
|
+
end
|
129
|
+
|
130
|
+
def v2_data_criteria_by_id
|
131
|
+
criteria_by_id = {}
|
132
|
+
@v2_data_criteria.each do |criteria|
|
133
|
+
criteria_by_id[criteria.id] = criteria
|
134
|
+
end
|
135
|
+
criteria_by_id
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def parse()
|
141
|
+
@doc[:data_criteria].each do |key,criteria|
|
142
|
+
parsed_criteria = HQMF::DataCriteriaConverter.convert(key, criteria)
|
143
|
+
@v2_data_criteria << parsed_criteria
|
144
|
+
@v1_data_criteria_by_id[criteria[:id]] = parsed_criteria
|
145
|
+
@specific_occurrences[parsed_criteria.id] = criteria[:derived_from] != nil
|
146
|
+
end
|
147
|
+
create_measure_period_v1_data_criteria(@doc,@measure_period,@v1_data_criteria_by_id)
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.convert(key, criteria)
|
151
|
+
|
152
|
+
# @param [String] id
|
153
|
+
# @param [String] title
|
154
|
+
# @param [String] standard_category
|
155
|
+
# @param [String] qds_data_type
|
156
|
+
# @param [String] subset_code
|
157
|
+
# @param [String] code_list_id
|
158
|
+
# @param [String] property
|
159
|
+
# @param [String] type
|
160
|
+
# @param [String] status
|
161
|
+
# @param [boolean] negation
|
162
|
+
# @param [String] negation_code_list_id
|
163
|
+
# @param [Value|Range|Coded] value
|
164
|
+
# @param [Range] effective_time
|
165
|
+
# @param [Hash<String,String>] inline_code_list
|
166
|
+
|
167
|
+
id = convert_key(key)
|
168
|
+
title = criteria[:title]
|
169
|
+
title = title.match(/.*:\s+(.+)/)[1]
|
170
|
+
description = criteria[:description]
|
171
|
+
code_list_id = criteria[:code_list_id]
|
172
|
+
definition = criteria[:definition]
|
173
|
+
status = criteria[:status]
|
174
|
+
negation = criteria[:negation]
|
175
|
+
negation_code_list_id = criteria[:negation_code_list_id]
|
176
|
+
specific_occurrence = criteria[:specific_occurrence]
|
177
|
+
specific_occurrence_const = criteria[:specific_occurrence_const]
|
178
|
+
|
179
|
+
value = nil # value is filled out by backfill_patient_characteristics for things like gender and by REFR restrictions
|
180
|
+
effective_time = nil # filled out by temporal reference code
|
181
|
+
temporal_references = # filled out by operator code
|
182
|
+
subset_operators = nil # filled out by operator code
|
183
|
+
children_criteria = nil # filled out by operator and temporal reference code
|
184
|
+
derivation_operator = nil # filled out by operator and temporal reference code
|
185
|
+
negation_code_list_id = nil # filled out by RSON restrictions
|
186
|
+
field_values = nil # field values are filled out by SUBJ and REFR restrictions
|
187
|
+
inline_code_list = nil # inline code list is only used in HQMF V2, so we can just pass in nil
|
188
|
+
display_name=nil
|
189
|
+
|
190
|
+
HQMF::DataCriteria.new(id, title, display_name, description, code_list_id, children_criteria, derivation_operator, definition, status,
|
191
|
+
value, field_values, effective_time, inline_code_list, negation, negation_code_list_id, temporal_references, subset_operators,specific_occurrence,specific_occurrence_const)
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
# this method creates V1 data criteria for the measurement period. These data criteria can be
|
197
|
+
# referenced properly within the restrictions
|
198
|
+
def create_measure_period_v1_data_criteria(doc,measure_period,v1_data_criteria_by_id)
|
199
|
+
|
200
|
+
attributes = doc[:attributes]
|
201
|
+
attributes.keys.each {|key| attributes[key.to_s] = attributes[key]}
|
202
|
+
|
203
|
+
measure_period_key = attributes['MEASUREMENT_PERIOD'][:id]
|
204
|
+
measure_start_key = attributes['MEASUREMENT_START_DATE'][:id]
|
205
|
+
measure_end_key = attributes['MEASUREMENT_END_DATE'][:id]
|
206
|
+
|
207
|
+
@measure_period_v1_keys = {measure_start: measure_start_key, measure_end: measure_end_key, measure_period: measure_period_key}
|
208
|
+
|
209
|
+
type = 'variable'
|
210
|
+
code_list_id,negation_code_list_id,property,status,field_values,effective_time,inline_code_list,children_criteria,derivation_operator,temporal_references,subset_operators=nil
|
211
|
+
|
212
|
+
#####
|
213
|
+
##
|
214
|
+
######### SET MEASURE PERIOD
|
215
|
+
##
|
216
|
+
#####
|
217
|
+
|
218
|
+
measure_period_id = HQMF::Document::MEASURE_PERIOD_ID
|
219
|
+
value = measure_period
|
220
|
+
measure_criteria = HQMF::DataCriteria.new(measure_period_id,measure_period_id,nil,measure_period_id,code_list_id,children_criteria,derivation_operator,measure_period_id,status,
|
221
|
+
value,field_values,effective_time,inline_code_list, false, nil, temporal_references,subset_operators,nil,nil)
|
222
|
+
|
223
|
+
# set the measure period data criteria for all measure period keys
|
224
|
+
v1_data_criteria_by_id[measure_period_key] = measure_criteria
|
225
|
+
v1_data_criteria_by_id[measure_start_key] = measure_criteria
|
226
|
+
v1_data_criteria_by_id[measure_end_key] = measure_criteria
|
227
|
+
@measure_period_criteria = measure_criteria
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
def self.title_from_description(title, description)
|
233
|
+
title.gsub(/^#{Regexp.escape(description).gsub('\\ ',':?,?\\ ')}:\s*/i,'')
|
234
|
+
end
|
235
|
+
|
236
|
+
def self.convert_key(key)
|
237
|
+
key.to_s.downcase.gsub('_', ' ').split(' ').map {|w| w.capitalize }.join('')
|
238
|
+
end
|
239
|
+
|
240
|
+
# Simple class to issue monotonically increasing integer identifiers
|
241
|
+
class Counter
|
242
|
+
def initialize
|
243
|
+
@count = 0
|
244
|
+
end
|
245
|
+
|
246
|
+
def next
|
247
|
+
@count+=1
|
248
|
+
end
|
249
|
+
end
|
250
|
+
@@ids = Counter.new
|
251
|
+
|
252
|
+
|
253
|
+
end
|
254
|
+
end
|