health-data-standards 3.7.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/health-data-standards.rb +3 -0
- data/lib/health-data-standards/export/helper/html_view_helper.rb +12 -12
- data/lib/health-data-standards/import/bulk_record_importer.rb +4 -4
- data/lib/health-data-standards/import/cda/encounter_importer.rb +2 -2
- data/lib/health-data-standards/models/admission_source.rb +11 -0
- data/lib/health-data-standards/models/adverse_event.rb +6 -0
- data/lib/health-data-standards/models/allergy.rb +2 -1
- data/lib/health-data-standards/models/assessment.rb +1 -0
- data/lib/health-data-standards/models/care_goal.rb +0 -1
- data/lib/health-data-standards/models/component.rb +14 -0
- data/lib/health-data-standards/models/encounter.rb +10 -13
- data/lib/health-data-standards/models/entry.rb +1 -1
- data/lib/health-data-standards/models/facility.rb +3 -2
- data/lib/health-data-standards/models/lab_result.rb +10 -4
- data/lib/health-data-standards/models/medication.rb +3 -0
- data/lib/health-data-standards/models/procedure.rb +7 -2
- data/lib/health-data-standards/models/record.rb +6 -2
- data/lib/health-data-standards/models/transfer.rb +0 -5
- data/lib/health-data-standards/util/hqmf_template_helper.rb +3 -2
- data/lib/health-data-standards/util/hqmfr2_template_oid_map.json +8 -0
- data/lib/health-data-standards/util/hqmfr2cql_template_oid_map.json +390 -0
- data/lib/health-data-standards/util/vs_api.rb +3 -3
- data/lib/hqmf-model/data_criteria.json +19 -1
- data/lib/hqmf-model/data_criteria.rb +31 -7
- data/lib/hqmf-model/document.rb +11 -2
- data/lib/hqmf-model/types.rb +31 -5
- data/lib/hqmf-parser.rb +7 -0
- data/lib/hqmf-parser/2.0/data_criteria.rb +4 -1
- data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_base_extract.rb +1 -1
- data/lib/hqmf-parser/2.0/document.rb +4 -4
- data/lib/hqmf-parser/2.0/document_helpers/doc_population_helper.rb +0 -2
- data/lib/hqmf-parser/2.0/population_criteria.rb +2 -2
- data/lib/hqmf-parser/2.0/value_set_helper.rb +4 -1
- data/lib/hqmf-parser/cql/data_criteria.rb +57 -0
- data/lib/hqmf-parser/cql/data_criteria_helpers/dc_definition_from_template_or_type_extract.rb +79 -0
- data/lib/hqmf-parser/cql/data_criteria_helpers/dc_post_processing.rb +43 -0
- data/lib/hqmf-parser/cql/document.rb +78 -0
- data/lib/hqmf-parser/cql/document_helpers/doc_population_helper.rb +124 -0
- data/lib/hqmf-parser/cql/value_set_helper.rb +103 -0
- data/lib/hqmf-parser/parser.rb +24 -1
- metadata +11 -1
@@ -0,0 +1,43 @@
|
|
1
|
+
module HQMF2CQL
|
2
|
+
# Processing on data criteria after the initial extractions have taken place
|
3
|
+
module DataCriteriaPostProcessing
|
4
|
+
extend HQMF2::DataCriteriaPostProcessing
|
5
|
+
|
6
|
+
# Handles settings values after (most) values have been setup
|
7
|
+
def post_processing
|
8
|
+
extract_code_list_path_and_result_value
|
9
|
+
|
10
|
+
# Prefix ids that start with numerical values, and strip tokens from others
|
11
|
+
@id = strip_tokens(@id)
|
12
|
+
@children_criteria.map! { |cc| strip_tokens(cc) }
|
13
|
+
|
14
|
+
# append "_source" to the criteria since all the source criteria are separated from the non-source with the "_source" identifier
|
15
|
+
# "_source" is added to the SDC ids so that we are not duplicating ids between source and non source data criteria lists
|
16
|
+
# the derived source data criteria maintain their original ids since they are duplicated in the data criteria and source data criteria lists from the simple xml
|
17
|
+
@source_data_criteria = "#{@id}_source" unless (@definition == 'derived' || @definition == 'satisfies_all' || @definition == 'satisfies_any')
|
18
|
+
@source_data_criteria = strip_tokens(@source_data_criteria) unless @source_data_criteria.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Extract the code_list_xpath and the criteria's value from any of the
|
22
|
+
# template ids (if multiple exist)
|
23
|
+
def extract_code_list_path_and_result_value
|
24
|
+
@template_ids.each do |t|
|
25
|
+
# NOTE! (Adam 6/14): The following logic should absolutely be changed
|
26
|
+
# when Bonnie CQL support goes production. The "try this then try
|
27
|
+
# that" approach is an artifact of the template oids changing as of
|
28
|
+
# MAT 5.3; we want to support measures exported using 5.3, but also
|
29
|
+
# measures that were exported using previous versions of the MAT.
|
30
|
+
|
31
|
+
# Try a lookup using the newer template oids.
|
32
|
+
mapping = HQMF2CQL::ValueSetHelper.get_mapping_for_template(t)
|
33
|
+
|
34
|
+
# If the new template oids didn't work, try a lookup using the older
|
35
|
+
# template oids.
|
36
|
+
mapping = HQMF2::ValueSetHelper.get_mapping_for_template(t)unless mapping
|
37
|
+
|
38
|
+
handle_mapping_template(mapping)
|
39
|
+
break if mapping # Quit if one template id with a mapping has set these values
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module HQMF2CQL
|
2
|
+
|
3
|
+
# Class representing a HQMF v2 document that uses CQL for measure logic.
|
4
|
+
class Document < HQMF2::Document
|
5
|
+
|
6
|
+
# Create a new HQMF2CQL::Document instance by parsing the given HQMF contents.
|
7
|
+
def initialize(hqmf_contents, use_default_measure_period = true)
|
8
|
+
# Set up basic measure values
|
9
|
+
setup_default_values(hqmf_contents, use_default_measure_period)
|
10
|
+
|
11
|
+
# Extract data criteria
|
12
|
+
extract_criteria
|
13
|
+
|
14
|
+
# Extract the population criteria and population collections
|
15
|
+
pop_helper = HQMF2CQL::DocumentPopulationHelper.new(@entry, @doc, self, @id_generator, @reference_ids)
|
16
|
+
# @populations_cql_map and @observations are needed by the frontend
|
17
|
+
@populations, @population_criteria, @populations_cql_map, @observations = pop_helper.extract_populations
|
18
|
+
@cql_measure_library = pop_helper.extract_main_library
|
19
|
+
end
|
20
|
+
|
21
|
+
# Generates this classes hqmf-model equivalent.
|
22
|
+
def to_model
|
23
|
+
dcs = all_data_criteria.compact.collect(&:to_model)
|
24
|
+
sdc = source_data_criteria.compact.collect(&:to_model)
|
25
|
+
pcs = all_population_criteria.compact.collect(&:to_model)
|
26
|
+
HQMF::Document.new(@id, @id, @hqmf_set_id, @hqmf_version_number, @cms_id,
|
27
|
+
title, description, pcs, dcs, sdc,
|
28
|
+
@attributes, @measure_period, @populations,
|
29
|
+
populations_cql_map=@populations_cql_map, cql_measure_library=@cql_measure_library, observations=@observations)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Extracts data criteria from the HQMF document.
|
33
|
+
def extract_criteria
|
34
|
+
# Grab each data criteria entry from the HQMF
|
35
|
+
extracted_data_criteria = []
|
36
|
+
@doc.xpath('cda:QualityMeasureDocument/cda:component/cda:dataCriteriaSection/cda:entry', NAMESPACES).each do |entry|
|
37
|
+
extracted_data_criteria << entry
|
38
|
+
dc = HQMF2CQL::DataCriteria.new(entry) # Create new data criteria
|
39
|
+
sdc = dc.clone # Clone data criteria
|
40
|
+
sdc.id += '_source' # Make it a source
|
41
|
+
|
42
|
+
@data_criteria << dc
|
43
|
+
@source_data_criteria << sdc
|
44
|
+
end
|
45
|
+
make_positive_entry
|
46
|
+
end
|
47
|
+
|
48
|
+
# This method is needed for situations when there is a only
|
49
|
+
# a negated version of a data criteria. Bonnie will only
|
50
|
+
# show the affirmative version of data criteria. This method
|
51
|
+
# will create an affirmative version of a data criteria when there
|
52
|
+
# is only the negative one in the HQMF.
|
53
|
+
def make_positive_entry
|
54
|
+
negated_criteria = []
|
55
|
+
data_criteria_index_lookup = []
|
56
|
+
# Find the criteria that are negated
|
57
|
+
# At the same time build a hash of all criteria and their code_list_id, definition, status, and negation status
|
58
|
+
@data_criteria.each_with_index do |criterion, source_index|
|
59
|
+
negated_criteria << criterion if criterion.negation
|
60
|
+
data_criteria_index_lookup << [criterion.code_list_id, criterion.definition, criterion.status, criterion.negation]
|
61
|
+
end
|
62
|
+
|
63
|
+
negated_criteria.each do |criterion|
|
64
|
+
# Check if there is a criterion with the same OID, definition and status BUT that isn't negated
|
65
|
+
unless data_criteria_index_lookup.include?([criterion.code_list_id, criterion.definition, criterion.status, false])
|
66
|
+
spoofed_positive_instance = criterion.clone
|
67
|
+
spoofed_positive_instance.make_criterion_positive
|
68
|
+
@data_criteria << spoofed_positive_instance
|
69
|
+
sdc = spoofed_positive_instance.clone
|
70
|
+
sdc.id += '_source'
|
71
|
+
@source_data_criteria << sdc
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module HQMF2CQL
|
2
|
+
# Handles generation of populations for the main document
|
3
|
+
class DocumentPopulationHelper < HQMF2::DocumentPopulationHelper
|
4
|
+
include HQMF2::Utilities
|
5
|
+
|
6
|
+
def extract_populations
|
7
|
+
@populations_cql_map = extract_populations_cql_map
|
8
|
+
extract_populations_and_criteria
|
9
|
+
# Return via destructuring
|
10
|
+
[@populations, @population_criteria, @populations_cql_map, @observations]
|
11
|
+
end
|
12
|
+
|
13
|
+
# Extracts potential measure observations from the CQL based HQMF.
|
14
|
+
# This function needs to return a boolean so that it will continue to work with
|
15
|
+
# HQMF2::DocumentPopulationHelper::extract_populations_and_criteria
|
16
|
+
# This function is being overridden because in CQL the observations are no longer data criteria in the HQMF.
|
17
|
+
def extract_observations
|
18
|
+
@observations = []
|
19
|
+
|
20
|
+
# Look for observations in the measureObservationSection of the CQL based HQMF document, and if they exist extract the name of the CQL statement that calculates the observation. This is the name of the "define function" statement in the CQL.
|
21
|
+
# In addition to the function name we also need to retreive the parameter for the function.
|
22
|
+
observation_section = @doc.xpath('/cda:QualityMeasureDocument/cda:component/cda:measureObservationSection',
|
23
|
+
HQMF2::Document::NAMESPACES)
|
24
|
+
unless observation_section.empty?
|
25
|
+
observation_section.each do |entry|
|
26
|
+
# Need to add population criteria for observations
|
27
|
+
criteria_id = 'OBSERV'
|
28
|
+
criteria = HQMF2::PopulationCriteria.new(entry.xpath('cda:definition'), @document, @id_generator)
|
29
|
+
criteria.type = 'OBSERV'
|
30
|
+
if @ids_by_hqmf_id["#{criteria.hqmf_id}"]
|
31
|
+
criteria.create_human_readable_id(@ids_by_hqmf_id[criteria.hqmf_id])
|
32
|
+
else
|
33
|
+
criteria.create_human_readable_id(population_id_with_counter(criteria_id))
|
34
|
+
@ids_by_hqmf_id["#{criteria.hqmf_id}"] = criteria.id
|
35
|
+
end
|
36
|
+
@population_criteria << criteria
|
37
|
+
|
38
|
+
# Extract CQL function specific details
|
39
|
+
cql_define_function = {}
|
40
|
+
# The at_xpath(...).values returns an array of a single element.
|
41
|
+
# The match returns an array and since we don't want the double quotes we take the second element
|
42
|
+
cql_define_function[:function_name] = entry.at_xpath("*/cda:measureObservationDefinition/cda:value/cda:expression").values.first.match('\\"([A-Za-z0-9 ]+)\\"')[1]
|
43
|
+
cql_define_function[:parameter] = entry.at_xpath("*/cda:measureObservationDefinition/cda:component/cda:criteriaReference/cda:id").attributes['extension'].value.match('\\"([A-Za-z0-9 ]+)\\"')[1]
|
44
|
+
@observations << cql_define_function
|
45
|
+
end
|
46
|
+
end
|
47
|
+
!@observations.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
# Generate the stratifications of populations, if any exist
|
51
|
+
# for CQL, adds 'population_index' and 'stratification_index'
|
52
|
+
def handle_stratifications(population_def, number_of_populations, population, id_def, population_index)
|
53
|
+
# handle stratifications (EP137, EP155)
|
54
|
+
stratifier_criteria_xpath = "cda:component/cda:stratifierCriteria[not(cda:component/cda:measureAttribute/cda:code[@code = 'SDE'])]/.."
|
55
|
+
population_def.xpath(stratifier_criteria_xpath, HQMF2::Document::NAMESPACES)
|
56
|
+
.each_with_index do |criteria_def, criteria_def_index|
|
57
|
+
# Skip this Stratification if any precondition doesn't contain any preconditions
|
58
|
+
next unless HQMF2::PopulationCriteria.new(criteria_def, @document, @id_generator)
|
59
|
+
.preconditions.all? { |prcn| prcn.preconditions.length > 0 }
|
60
|
+
index = number_of_populations + ((population_index - 1) * criteria_def.xpath('./*/cda:precondition').length) +
|
61
|
+
criteria_def_index
|
62
|
+
criteria_id = HQMF::PopulationCriteria::STRAT
|
63
|
+
stratified_population = population.dup
|
64
|
+
stratified_population['stratification'] = criteria_def.at_xpath('./*/cda:id/@root').try(:value) ||
|
65
|
+
"#{criteria_id}-#{criteria_def_index}"
|
66
|
+
build_population_criteria(criteria_def, criteria_id, stratified_population)
|
67
|
+
|
68
|
+
stratified_population['id'] = id_def ? "#{id_def.value} - Stratification #{criteria_def_index + 1}" : "Population#{index}"
|
69
|
+
title_def = population_def.at_xpath('cda:title/@value', HQMF2::Document::NAMESPACES)
|
70
|
+
stratified_population['title'] = title_def ? "#{title_def.value} - Stratification #{criteria_def_index + 1}" : "Population #{index}"
|
71
|
+
stratified_population['population_index'] = population_index
|
72
|
+
stratified_population['stratification_index'] = criteria_def_index
|
73
|
+
@stratifications << stratified_population
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Extracts the mappings between actual HQMF populations and their
|
78
|
+
# corresponding CQL define statements.
|
79
|
+
def extract_populations_cql_map
|
80
|
+
populations_cql_map = {}
|
81
|
+
@doc.xpath("//cda:populationCriteriaSection/cda:component[@typeCode='COMP']", HQMF2::Document::NAMESPACES).each do |population_def|
|
82
|
+
{
|
83
|
+
HQMF::PopulationCriteria::IPP => 'initialPopulationCriteria',
|
84
|
+
HQMF::PopulationCriteria::DENOM => 'denominatorCriteria',
|
85
|
+
HQMF::PopulationCriteria::NUMER => 'numeratorCriteria',
|
86
|
+
HQMF::PopulationCriteria::NUMEX => 'numeratorExclusionCriteria',
|
87
|
+
HQMF::PopulationCriteria::DENEXCEP => 'denominatorExceptionCriteria',
|
88
|
+
HQMF::PopulationCriteria::DENEX => 'denominatorExclusionCriteria',
|
89
|
+
HQMF::PopulationCriteria::MSRPOPL => 'measurePopulationCriteria',
|
90
|
+
HQMF::PopulationCriteria::MSRPOPLEX => 'measurePopulationExclusionCriteria',
|
91
|
+
HQMF::PopulationCriteria::STRAT => 'stratifierCriteria'
|
92
|
+
}.each_pair do |criteria_id, criteria_element_name|
|
93
|
+
criteria_def = population_def.at_xpath("cda:#{criteria_element_name}", HQMF2::Document::NAMESPACES)
|
94
|
+
if criteria_def
|
95
|
+
# Ignore Supplemental Data Elements
|
96
|
+
next if HQMF::PopulationCriteria::STRAT == criteria_id &&
|
97
|
+
!criteria_def.xpath("cda:component[@typeCode='COMP']/cda:measureAttribute/cda:code[@code='SDE']").empty?
|
98
|
+
cql_statement = criteria_def.at_xpath("*/*/cda:id", HQMF2::Document::NAMESPACES).attribute('extension').to_s.match(/"([^"]*)"/)
|
99
|
+
if populations_cql_map[criteria_id].nil?
|
100
|
+
populations_cql_map[criteria_id] = []
|
101
|
+
end
|
102
|
+
cql_statement = cql_statement.to_s.delete('\\"')
|
103
|
+
populations_cql_map[criteria_id].push cql_statement
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
populations_cql_map
|
108
|
+
end
|
109
|
+
|
110
|
+
# Extracts the name of the main cql library from the Population Criteria Section.
|
111
|
+
def extract_main_library
|
112
|
+
population_criteria_sections = @doc.xpath("//cda:populationCriteriaSection/cda:component[@typeCode='COMP']", HQMF2::Document::NAMESPACES)
|
113
|
+
criteria_section = population_criteria_sections.at_xpath("cda:initialPopulationCriteria", HQMF2::Document::NAMESPACES)
|
114
|
+
if criteria_section
|
115
|
+
# Example: the full name for the population criteria section is "BonnieNesting01.\"Initial Population\""
|
116
|
+
# The regex returns everything before the "." (BonnieNesting01), which is the file name of the cql measure
|
117
|
+
cql_main_library_name = criteria_section.at_xpath("*/*/cda:id", HQMF2::Document::NAMESPACES).attribute('extension').to_s.match(/[^.]*/).to_s
|
118
|
+
else
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module HQMF2CQL
|
2
|
+
# Class containing value set information
|
3
|
+
class ValueSetHelper
|
4
|
+
# rubocop:disable Metrics/LineLength
|
5
|
+
VALUESET_MAP = {
|
6
|
+
'2.16.840.1.113883.10.20.28.4.7' => { valueset_path: './*/cda:value', result_path: nil },
|
7
|
+
'2.16.840.1.113883.10.20.28.4.8' => { valueset_path: './*/cda:code', result_path: nil },
|
8
|
+
'2.16.840.1.113883.10.20.28.4.9' => { valueset_path: './*/cda:code', result_path: nil },
|
9
|
+
'2.16.840.1.113883.10.20.28.4.10' => { valueset_path: './*/cda:code', result_path: nil },
|
10
|
+
'2.16.840.1.113883.10.20.28.4.11' => { valueset_path: "./*/cda:participation[@typeCode='PRD']/cda:role[@classCode='MANU']/cda:playingDevice[@classCode='DEV']/cda:code", result_path: nil },
|
11
|
+
'2.16.840.1.113883.10.20.28.4.12' => { valueset_path: "./*/cda:participation[@typeCode='PRD']/cda:role[@classCode='MANU']/cda:playingDevice[@classCode='DEV']/cda:code", result_path: nil },
|
12
|
+
'2.16.840.1.113883.10.20.28.4.13' => { valueset_path: "./*/cda:participation[@typeCode='DEV']/cda:role[@classCode='MANU']/cda:playingDevice[@classCode='DEV']/cda:code", result_path: nil },
|
13
|
+
'2.16.840.1.113883.10.20.28.4.14' => { valueset_path: "./*/cda:participation[@typeCode='PRD']/cda:role[@classCode='MANU']/cda:playingDevice[@classCode='DEV']/cda:code", result_path: nil },
|
14
|
+
'2.16.840.1.113883.10.20.28.4.15' => { valueset_path: "./*/cda:participation[@typeCode='DEV']/cda:role[@classCode='MANU']/cda:playingDevice[@classCode='DEV']/cda:code", result_path: nil },
|
15
|
+
'2.16.840.1.113883.10.20.28.4.16' => { valueset_path: "./*/cda:participation[@typeCode='DEV']/cda:role[@classCode='MANU']/cda:playingDevice[@classCode='DEV']/cda:code", result_path: nil },
|
16
|
+
'2.16.840.1.113883.10.20.28.4.1' => { valueset_path: './*/cda:value', result_path: nil },
|
17
|
+
'2.16.840.1.113883.10.20.28.4.17' => { valueset_path: './*/cda:value', result_path: nil },
|
18
|
+
'2.16.840.1.113883.10.20.28.4.18' => { valueset_path: './*/cda:value', result_path: nil },
|
19
|
+
'2.16.840.1.113883.10.20.28.4.19' => { valueset_path: './*/cda:value', result_path: nil },
|
20
|
+
'2.16.840.1.113883.10.20.28.4.20' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS']/cda:observationCriteria/cda:code", result_path: nil },
|
21
|
+
'2.16.840.1.113883.10.20.28.4.21' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS']/cda:observationCriteria/cda:code", result_path: nil },
|
22
|
+
'2.16.840.1.113883.10.20.28.4.22' => { valueset_path: './*/cda:code', result_path: nil },
|
23
|
+
'2.16.840.1.113883.10.20.28.4.23' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
24
|
+
'2.16.840.1.113883.10.20.28.4.24' => { valueset_path: './*/cda:code', result_path: nil },
|
25
|
+
'2.16.840.1.113883.10.20.28.4.26' => { valueset_path: './*/cda:code', result_path: nil },
|
26
|
+
'2.16.840.1.113883.10.20.28.4.27' => { valueset_path: './*/cda:code', result_path: nil },
|
27
|
+
'2.16.840.1.113883.10.20.28.4.5' => { valueset_path: './*/cda:code', result_path: nil },
|
28
|
+
'2.16.840.1.113883.10.20.28.4.28' => { valueset_path: './*/cda:code', result_path: nil },
|
29
|
+
'2.16.840.1.113883.10.20.28.4.29' => { valueset_path: './*/cda:code', result_path: nil },
|
30
|
+
'2.16.840.1.113883.10.20.28.4.30' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
31
|
+
'2.16.840.1.113883.10.20.28.4.31' => { valueset_path: './*/cda:code', result_path: nil },
|
32
|
+
'2.16.840.1.113883.10.20.28.4.33' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS' and @inversionInd='true']/cda:procedureCriteria/cda:code", result_path: nil },
|
33
|
+
'2.16.840.1.113883.10.20.28.4.34' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS']/cda:actCriteria/cda:code", result_path: nil },
|
34
|
+
'2.16.840.1.113883.10.20.28.4.35' => { valueset_path: './*/cda:code', result_path: nil },
|
35
|
+
'2.16.840.1.113883.10.20.28.4.36' => { valueset_path: './*/cda:code', result_path: "./*/cda:outboundRelationship[@typeCode='REFR']//cda:code[@code='394617004']/../cda:value" },
|
36
|
+
'2.16.840.1.113883.10.20.28.4.37' => { valueset_path: './*/cda:code', result_path: nil },
|
37
|
+
'2.16.840.1.113883.10.20.28.4.39' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS']/cda:observationCriteria/cda:code", result_path: nil },
|
38
|
+
'2.16.840.1.113883.10.20.28.4.40' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS']/cda:observationCriteria/cda:code", result_path: nil },
|
39
|
+
'2.16.840.1.113883.10.20.28.4.41' => { valueset_path: './*/cda:code', result_path: nil },
|
40
|
+
'2.16.840.1.113883.10.20.28.4.42' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
41
|
+
'2.16.840.1.113883.10.20.28.4.43' => { valueset_path: './*/cda:code', result_path: nil },
|
42
|
+
'2.16.840.1.113883.10.20.28.4.44' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role/cda:playingMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
43
|
+
'2.16.840.1.113883.10.20.28.4.45' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingManufacturedMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
44
|
+
'2.16.840.1.113883.10.20.28.4.46' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil },
|
45
|
+
'2.16.840.1.113883.10.20.28.4.47' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil },
|
46
|
+
'2.16.840.1.113883.10.20.28.4.48' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingManufacturedMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
47
|
+
'2.16.840.1.113883.10.20.28.4.49' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
48
|
+
'2.16.840.1.113883.10.20.28.4.50' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
49
|
+
'2.16.840.1.113883.10.20.28.4.51' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
50
|
+
'2.16.840.1.113883.10.20.28.4.52' => { valueset_path: './*/cda:value', result_path: nil },
|
51
|
+
'2.16.840.1.113883.10.20.28.4.53' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
52
|
+
'2.16.840.1.113883.10.20.28.4.6' => { valueset_path: './*/cda:value', result_path: nil },
|
53
|
+
'2.16.840.1.113883.10.20.28.4.54' => { valueset_path: nil, result_path: nil },
|
54
|
+
'2.16.840.1.113883.10.20.28.4.56' => { valueset_path: './*/cda:value', result_path: nil },
|
55
|
+
'2.16.840.1.113883.10.20.28.4.57' => { valueset_path: './*/cda:value', result_path: nil },
|
56
|
+
'2.16.840.1.113883.10.20.28.4.58' => { valueset_path: './*/cda:value', result_path: nil },
|
57
|
+
'2.16.840.1.113883.10.20.28.4.59' => { valueset_path: './*/cda:value', result_path: nil },
|
58
|
+
'2.16.840.1.113883.10.20.28.4.55' => { valueset_path: './*/cda:value', result_path: nil },
|
59
|
+
'2.16.840.1.113883.10.20.28.4.86' => { valueset_path: './*/cda:value', result_path: nil },
|
60
|
+
'2.16.840.1.113883.10.20.28.4.61' => { valueset_path: './*/cda:value', result_path: nil },
|
61
|
+
'2.16.840.1.113883.10.20.28.4.62' => { valueset_path: './*/cda:value', result_path: "./*/cda:outboundRelationship[@typeCode='REFR']//cda:code[@code='394617004']/../cda:value" },
|
62
|
+
'2.16.840.1.113883.10.20.28.4.63' => { valueset_path: './*/cda:value', result_path: nil },
|
63
|
+
'2.16.840.1.113883.10.20.28.4.64' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS' and @inversionInd='true']/cda:procedureCriteria/cda:code", result_path: nil },
|
64
|
+
'2.16.840.1.113883.10.20.28.4.65' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='CAUS' and @inversionInd='true']/cda:procedureCriteria/cda:code", result_path: nil },
|
65
|
+
'2.16.840.1.113883.10.20.28.4.66' => { valueset_path: './*/cda:code', result_path: nil },
|
66
|
+
'2.16.840.1.113883.10.20.28.4.67' => { valueset_path: './*/cda:code', result_path: "./*/cda:outboundRelationship[@typeCode='REFR']//cda:code[@code='394617004']/../cda:value" },
|
67
|
+
'2.16.840.1.113883.10.20.28.4.68' => { valueset_path: './*/cda:code', result_path: nil },
|
68
|
+
'2.16.840.1.113883.10.20.28.4.70' => { valueset_path: './*/cda:value', result_path: nil },
|
69
|
+
'2.16.840.1.113883.10.20.28.4.71' => { valueset_path: "./*/cda:participation/cda:role[@classCode='ASSIGNED']/cda:playingDevice[@classCode='DEV' and @determinerCode='KIND']/cda:code", result_path: nil },
|
70
|
+
'2.16.840.1.113883.10.20.28.4.87' => { valueset_path: './*/cda:value', result_path: nil },
|
71
|
+
'2.16.840.1.113883.10.20.28.4.72' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
72
|
+
'2.16.840.1.113883.10.20.28.4.93' => { valueset_path: './*/cda:value', result_path: nil },
|
73
|
+
'2.16.840.1.113883.10.20.28.4.73' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
74
|
+
'2.16.840.1.113883.10.20.28.4.74' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
75
|
+
'2.16.840.1.113883.10.20.28.4.75' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
76
|
+
'2.16.840.1.113883.10.20.28.4.76' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
77
|
+
'2.16.840.1.113883.10.20.28.4.77' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
78
|
+
'2.16.840.1.113883.10.20.28.4.78' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingMaterial[@classCode='MMAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
79
|
+
'2.16.840.1.113883.10.20.28.4.79' => { valueset_path: './*/cda:value', result_path: nil },
|
80
|
+
'2.16.840.1.113883.10.20.28.4.80' => { valueset_path: './*/cda:value', result_path: nil },
|
81
|
+
'2.16.840.1.113883.10.20.28.4.81' => { valueset_path: './*/cda:value', result_path: nil },
|
82
|
+
'2.16.840.1.113883.10.20.28.4.82' => { valueset_path: './*/cda:value', result_path: nil },
|
83
|
+
'2.16.840.1.113883.10.20.28.4.84' => { valueset_path: "./*/cda:participation[@typeCode='ORG']/cda:role[@classCode='LOCE']/cda:code", result_path: nil },
|
84
|
+
'2.16.840.1.113883.10.20.28.4.85' => { valueset_path: "./*/cda:participation[@typeCode='ORG']/cda:role[@classCode='LOCE']/cda:code", result_path: nil },
|
85
|
+
'2.16.840.1.113883.10.20.28.4.110' => { valueset_path: './*/cda:value', result_path: nil },
|
86
|
+
'2.16.840.1.113883.10.20.28.4.111' => { valueset_path: './*/cda:value', result_path: nil },
|
87
|
+
'2.16.840.1.113883.10.20.28.4.112' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role/cda:playingManufacturedMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
88
|
+
'2.16.840.1.113883.10.20.28.4.113' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role/cda:playingManufacturedMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
89
|
+
'2.16.840.1.113883.10.20.28.4.114' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil },
|
90
|
+
'2.16.840.1.113883.10.20.28.4.115' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role/cda:playingMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
91
|
+
'2.16.840.1.113883.10.20.28.4.116' => { valueset_path: './*/cda:value', result_path: nil },
|
92
|
+
'2.16.840.1.113883.10.20.28.4.117' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
93
|
+
'2.16.840.1.113883.10.20.28.4.118' => { valueset_path: './*/cda:code', result_path: nil },
|
94
|
+
'2.16.840.1.113883.10.20.28.4.119' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil },
|
95
|
+
'2.16.840.1.113883.10.20.28.4.120' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil }
|
96
|
+
}
|
97
|
+
# rubocop:enable Metrics/LineLength
|
98
|
+
|
99
|
+
def self.get_mapping_for_template(template)
|
100
|
+
VALUESET_MAP[template]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/hqmf-parser/parser.rb
CHANGED
@@ -4,6 +4,7 @@ module HQMF
|
|
4
4
|
HQMF_VERSION_1 = "1.0"
|
5
5
|
HQMF_VERSION_2 = "2.0"
|
6
6
|
|
7
|
+
# HQMF v2 Parser for measures that use QDM for measure logic
|
7
8
|
class V2Parser
|
8
9
|
def initialize
|
9
10
|
end
|
@@ -13,7 +14,7 @@ module HQMF
|
|
13
14
|
HQMF2::Document.new(xml_contents).to_model
|
14
15
|
end
|
15
16
|
|
16
|
-
def
|
17
|
+
def parse_fields(xml_contents)
|
17
18
|
result = {}
|
18
19
|
doc = HQMF2::Document.parse(xml_contents)
|
19
20
|
type = doc.at_xpath('/cda:QualityMeasureDocument/cda:code/@code').value
|
@@ -39,6 +40,28 @@ module HQMF
|
|
39
40
|
|
40
41
|
end
|
41
42
|
|
43
|
+
# HQMF v2 Parser for measures that use CQL for measure logic
|
44
|
+
class V2CQLParser < V2Parser
|
45
|
+
|
46
|
+
def parse(xml_contents, codes=nil)
|
47
|
+
HQMF::Counter.instance.reset()
|
48
|
+
HQMF2CQL::Document.new(xml_contents).to_model
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.valid?(xml_contents)
|
52
|
+
doc = HQMF2::Document.parse(xml_contents)
|
53
|
+
hqmf2 = !doc.at_xpath("/cda:QualityMeasureDocument/cda:typeId[@root='2.16.840.1.113883.1.3' and @extension='POQM_HD000001UV02']").nil?
|
54
|
+
cql = !doc.at_xpath("/cda:QualityMeasureDocument/cda:relatedDocument/cda:expressionDocument/cda:text[@mediaType='application/cql']").nil?
|
55
|
+
if !cql
|
56
|
+
# The media type changed for MAT version 5.3
|
57
|
+
cql = !doc.at_xpath("/cda:QualityMeasureDocument/cda:relatedDocument/cda:expressionDocument/cda:text[@mediaType='text/cql']").nil?
|
58
|
+
end
|
59
|
+
hqmf2 && cql
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
# HQMF v1 Parser for measures that use QDM for measure logic
|
42
65
|
class V1Parser
|
43
66
|
|
44
67
|
def parse(xml_contents, codes=nil)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: health-data-standards
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The MITRE Corporation
|
@@ -304,6 +304,8 @@ files:
|
|
304
304
|
- lib/health-data-standards/import/hdata/metadata_importer.rb
|
305
305
|
- lib/health-data-standards/import/provider_import_utils.rb
|
306
306
|
- lib/health-data-standards/models/address.rb
|
307
|
+
- lib/health-data-standards/models/admission_source.rb
|
308
|
+
- lib/health-data-standards/models/adverse_event.rb
|
307
309
|
- lib/health-data-standards/models/allergy.rb
|
308
310
|
- lib/health-data-standards/models/assessment.rb
|
309
311
|
- lib/health-data-standards/models/care_experience.rb
|
@@ -311,6 +313,7 @@ files:
|
|
311
313
|
- lib/health-data-standards/models/cda_identifier.rb
|
312
314
|
- lib/health-data-standards/models/coded_result_value.rb
|
313
315
|
- lib/health-data-standards/models/communication.rb
|
316
|
+
- lib/health-data-standards/models/component.rb
|
314
317
|
- lib/health-data-standards/models/condition.rb
|
315
318
|
- lib/health-data-standards/models/cqm/aggregate_objects.rb
|
316
319
|
- lib/health-data-standards/models/cqm/bundle.rb
|
@@ -373,6 +376,7 @@ files:
|
|
373
376
|
- lib/health-data-standards/util/hqmf_template_helper.rb
|
374
377
|
- lib/health-data-standards/util/hqmf_template_oid_map.json
|
375
378
|
- lib/health-data-standards/util/hqmfr2_template_oid_map.json
|
379
|
+
- lib/health-data-standards/util/hqmfr2cql_template_oid_map.json
|
376
380
|
- lib/health-data-standards/util/nlm_helper.rb
|
377
381
|
- lib/health-data-standards/util/vs_api.rb
|
378
382
|
- lib/health-data-standards/validate/base_validator.rb
|
@@ -467,6 +471,12 @@ files:
|
|
467
471
|
- lib/hqmf-parser/converter/pass1/simple_restriction.rb
|
468
472
|
- lib/hqmf-parser/converter/pass2/comparison_converter.rb
|
469
473
|
- lib/hqmf-parser/converter/pass2/operator_converter.rb
|
474
|
+
- lib/hqmf-parser/cql/data_criteria.rb
|
475
|
+
- lib/hqmf-parser/cql/data_criteria_helpers/dc_definition_from_template_or_type_extract.rb
|
476
|
+
- lib/hqmf-parser/cql/data_criteria_helpers/dc_post_processing.rb
|
477
|
+
- lib/hqmf-parser/cql/document.rb
|
478
|
+
- lib/hqmf-parser/cql/document_helpers/doc_population_helper.rb
|
479
|
+
- lib/hqmf-parser/cql/value_set_helper.rb
|
470
480
|
- lib/hqmf-parser/parser.rb
|
471
481
|
- lib/util/counter.rb
|
472
482
|
- resources/schema/infrastructure/cda/CDA_SDTC.xsd
|