hqmf-parser 1.0.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.
- 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
|