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.
Files changed (49) hide show
  1. data/Gemfile +23 -0
  2. data/README.md +903 -0
  3. data/Rakefile +19 -0
  4. data/VERSION +1 -0
  5. data/lib/hqmf-generator/hqmf-generator.rb +308 -0
  6. data/lib/hqmf-model/attribute.rb +35 -0
  7. data/lib/hqmf-model/data_criteria.rb +322 -0
  8. data/lib/hqmf-model/document.rb +172 -0
  9. data/lib/hqmf-model/population_criteria.rb +90 -0
  10. data/lib/hqmf-model/precondition.rb +85 -0
  11. data/lib/hqmf-model/types.rb +318 -0
  12. data/lib/hqmf-model/utilities.rb +52 -0
  13. data/lib/hqmf-parser.rb +54 -0
  14. data/lib/hqmf-parser/1.0/attribute.rb +68 -0
  15. data/lib/hqmf-parser/1.0/comparison.rb +34 -0
  16. data/lib/hqmf-parser/1.0/data_criteria.rb +105 -0
  17. data/lib/hqmf-parser/1.0/document.rb +209 -0
  18. data/lib/hqmf-parser/1.0/expression.rb +52 -0
  19. data/lib/hqmf-parser/1.0/population_criteria.rb +79 -0
  20. data/lib/hqmf-parser/1.0/precondition.rb +89 -0
  21. data/lib/hqmf-parser/1.0/range.rb +65 -0
  22. data/lib/hqmf-parser/1.0/restriction.rb +157 -0
  23. data/lib/hqmf-parser/1.0/utilities.rb +41 -0
  24. data/lib/hqmf-parser/2.0/data_criteria.rb +319 -0
  25. data/lib/hqmf-parser/2.0/document.rb +165 -0
  26. data/lib/hqmf-parser/2.0/population_criteria.rb +53 -0
  27. data/lib/hqmf-parser/2.0/precondition.rb +44 -0
  28. data/lib/hqmf-parser/2.0/types.rb +223 -0
  29. data/lib/hqmf-parser/2.0/utilities.rb +30 -0
  30. data/lib/hqmf-parser/converter/pass1/data_criteria_converter.rb +254 -0
  31. data/lib/hqmf-parser/converter/pass1/document_converter.rb +183 -0
  32. data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +135 -0
  33. data/lib/hqmf-parser/converter/pass1/precondition_converter.rb +164 -0
  34. data/lib/hqmf-parser/converter/pass1/precondition_extractor.rb +159 -0
  35. data/lib/hqmf-parser/converter/pass1/simple_data_criteria.rb +35 -0
  36. data/lib/hqmf-parser/converter/pass1/simple_operator.rb +89 -0
  37. data/lib/hqmf-parser/converter/pass1/simple_population_criteria.rb +10 -0
  38. data/lib/hqmf-parser/converter/pass1/simple_precondition.rb +63 -0
  39. data/lib/hqmf-parser/converter/pass1/simple_restriction.rb +64 -0
  40. data/lib/hqmf-parser/converter/pass2/comparison_converter.rb +91 -0
  41. data/lib/hqmf-parser/converter/pass2/operator_converter.rb +169 -0
  42. data/lib/hqmf-parser/converter/pass3/specific_occurrence_converter.rb +86 -0
  43. data/lib/hqmf-parser/converter/pass3/specific_occurrence_converter_bak.rb +70 -0
  44. data/lib/hqmf-parser/parser.rb +22 -0
  45. data/lib/hqmf-parser/value_sets/value_set_parser.rb +206 -0
  46. data/lib/tasks/coverme.rake +8 -0
  47. data/lib/tasks/hqmf.rake +141 -0
  48. data/lib/tasks/value_sets.rake +23 -0
  49. metadata +159 -0
@@ -0,0 +1,319 @@
1
+ module HQMF2
2
+ # Represents a data criteria specification
3
+ class DataCriteria
4
+
5
+ include HQMF2::Utilities
6
+
7
+ attr_reader :property, :type, :status, :value, :effective_time, :section
8
+ attr_reader :temporal_references, :subset_operators, :children_criteria
9
+ attr_reader :derivation_operator, :negation, :negation_code_list_id, :description
10
+ attr_reader :field_values, :source_data_criteria, :specific_occurrence_const
11
+ attr_reader :specific_occurrence, :is_source_data_criteria
12
+
13
+ # Create a new instance based on the supplied HQMF entry
14
+ # @param [Nokogiri::XML::Element] entry the parsed HQMF entry
15
+ def initialize(entry)
16
+ @entry = entry
17
+ @status = attr_val('./*/cda:statusCode/@code')
18
+ @description = attr_val('./*/cda:text/@value')
19
+ extract_negation()
20
+ extract_specific_or_source()
21
+ @effective_time = extract_effective_time
22
+ @temporal_references = extract_temporal_references
23
+ @derivation_operator = extract_derivation_operator
24
+ @field_values = extract_field_values
25
+ @subset_operators = extract_subset_operators
26
+ @children_criteria = extract_child_criteria
27
+ @id_xpath = './*/cda:id/cda:item/@extension'
28
+ @code_list_xpath = './*/cda:code'
29
+ @value_xpath = './*/cda:value'
30
+
31
+ # Try to determine what kind of data criteria we are dealing with
32
+ # First we look for a template id and if we find one just use the definition
33
+ # status and negation associated with that
34
+ if !extract_type_from_template_id()
35
+ # If no template id or not one we recognize then try to determine type from
36
+ # the definition element
37
+ extract_type_from_definition()
38
+ end
39
+
40
+ patch_xpaths_for_criteria_type()
41
+ end
42
+
43
+ def patch_xpaths_for_criteria_type
44
+ # Patch xpaths when necessary, HQMF data criteria are irregular in structure so
45
+ # the same information is found in different places depending on the type of
46
+ # criteria
47
+ # Assumes @definition and @status are already set
48
+ case @definition
49
+ when 'diagnosis', 'diagnosis_family_history'
50
+ @code_list_xpath = './cda:observationCriteria/cda:value'
51
+ when 'risk_category_assessment', 'procedure_result', 'laboratory_test', 'diagnostic_study_result', 'functional_status_result', 'intervention_result'
52
+ @value = extract_value
53
+ when 'medication'
54
+ case @status
55
+ when 'dispensed', 'ordered'
56
+ @code_list_xpath = './cda:supplyCriteria/cda:participation/cda:role/cda:code'
57
+ else # active or administered
58
+ @code_list_xpath = './cda:substanceAdministrationCriteria/cda:participation/cda:role/cda:code'
59
+ end
60
+ when 'patient_characteristic', 'patient_characteristic_birthdate', 'patient_characteristic_clinical_trial_participant', 'patient_characteristic_expired', 'patient_characteristic_gender', 'patient_characteristic_age', 'patient_characteristic_languages', 'patient_characteristic_marital_status', 'patient_characteristic_race'
61
+ @value = extract_value
62
+ when 'variable'
63
+ @value = extract_value
64
+ end
65
+ end
66
+
67
+ def extract_type_from_definition
68
+ # See if we can find a match for the entry definition value and status.
69
+ entry_type = attr_val('./*/cda:definition/*/cda:id/@extension')
70
+ begin
71
+ settings = HQMF::DataCriteria.get_settings_for_definition(entry_type, @status)
72
+ @definition = entry_type
73
+ rescue
74
+ # if no exact match then try a string match just using entry definition value
75
+ case entry_type
76
+ when 'Problem', 'Problems'
77
+ @definition = 'diagnosis'
78
+ when 'Encounter', 'Encounters'
79
+ @definition = 'encounter'
80
+ when 'LabResults', 'Results'
81
+ @definition = 'laboratory_test'
82
+ when 'Procedure', 'Procedures'
83
+ @definition = 'procedure'
84
+ when 'Medication', 'Medications'
85
+ @definition = 'medication'
86
+ if !@status
87
+ @status = 'active'
88
+ end
89
+ when 'RX'
90
+ @definition = 'medication'
91
+ if !@status
92
+ @status = 'dispensed'
93
+ end
94
+ when 'Demographics'
95
+ @definition = definition_for_demographic
96
+ when 'Derived'
97
+ @definition = 'derived'
98
+ when nil
99
+ @definition = 'variable'
100
+ else
101
+ raise "Unknown data criteria template identifier [#{entry_type}]"
102
+ end
103
+ end
104
+ end
105
+
106
+ def extract_type_from_template_id
107
+ template_ids = @entry.xpath('./*/cda:templateId/cda:item', HQMF2::Document::NAMESPACES).collect do |template_def|
108
+ HQMF2::Utilities.attr_val(template_def, '@root')
109
+ end
110
+ if template_ids.include?(HQMF::DataCriteria::SOURCE_DATA_CRITERIA_TEMPLATE_ID)
111
+ @is_source_data_criteria = true
112
+ end
113
+ template_ids.each do |template_id|
114
+ defs = HQMF::DataCriteria.definition_for_template_id(template_id)
115
+ if defs
116
+ @definition = defs['definition']
117
+ @status = defs['status'].length > 0 ? defs['status'] : nil
118
+ @negation = defs['negation']
119
+ return true
120
+ end
121
+ end
122
+ false
123
+ end
124
+
125
+ def to_s
126
+ props = {
127
+ :property => property,
128
+ :type => type,
129
+ :status => status,
130
+ :section => section
131
+ }
132
+ "DataCriteria#{props.to_s}"
133
+ end
134
+
135
+ # Get the identifier of the criteria, used elsewhere within the document for referencing
136
+ # @return [String] the identifier of this data criteria
137
+ def id
138
+ attr_val(@id_xpath)
139
+ end
140
+
141
+ # Get the title of the criteria, provides a human readable description
142
+ # @return [String] the title of this data criteria
143
+ def title
144
+ attr_val("#{@code_list_xpath}/cda:displayName/@value") || id
145
+ end
146
+
147
+ # Get the code list OID of the criteria, used as an index to the code list database
148
+ # @return [String] the code list identifier of this data criteria
149
+ def code_list_id
150
+ attr_val("#{@code_list_xpath}/@valueSet")
151
+ end
152
+
153
+ def inline_code_list
154
+ codeSystem = attr_val("#{@code_list_xpath}/@codeSystem")
155
+ if codeSystem
156
+ codeSystemName = HealthDataStandards::Util::CodeSystemHelper.code_system_for(codeSystem)
157
+ else
158
+ codeSystemName = attr_val("#{@code_list_xpath}/@codeSystemName")
159
+ end
160
+ codeValue = attr_val("#{@code_list_xpath}/@code")
161
+ if codeSystemName && codeValue
162
+ {codeSystemName => [codeValue]}
163
+ else
164
+ nil
165
+ end
166
+ end
167
+
168
+ def to_model
169
+ mv = value ? value.to_model : nil
170
+ met = effective_time ? effective_time.to_model : nil
171
+ mtr = temporal_references.collect {|ref| ref.to_model}
172
+ mso = subset_operators.collect {|opr| opr.to_model}
173
+ field_values = {}
174
+ @field_values.each_pair do |id, val|
175
+ field_values[id] = val.to_model
176
+ end
177
+
178
+ HQMF::DataCriteria.new(id, title, nil, description, code_list_id, children_criteria,
179
+ derivation_operator, @definition, status, mv, field_values, met, inline_code_list,
180
+ @negation, @negation_code_list_id, mtr, mso, @specific_occurrence,
181
+ @specific_occurrence_const, @source_data_criteria)
182
+ end
183
+
184
+ private
185
+
186
+ def extract_negation
187
+ negation = attr_val('./*/@actionNegationInd')
188
+ @negation = (negation=='true')
189
+ if @negation
190
+ @negation_code_list_id = attr_val('./*/cda:reasonCode/cda:item/@valueSet')
191
+ else
192
+ @negation_code_list_id = nil
193
+ end
194
+ end
195
+
196
+ def extract_child_criteria
197
+ @entry.xpath('./*/cda:excerpt/*/cda:id', HQMF2::Document::NAMESPACES).collect do |ref|
198
+ Reference.new(ref).id
199
+ end.compact
200
+ end
201
+
202
+ def extract_effective_time
203
+ effective_time_def = @entry.at_xpath('./*/cda:effectiveTime', HQMF2::Document::NAMESPACES)
204
+ if effective_time_def
205
+ EffectiveTime.new(effective_time_def)
206
+ else
207
+ nil
208
+ end
209
+ end
210
+
211
+ def all_subset_operators
212
+ @entry.xpath('./*/cda:excerpt', HQMF2::Document::NAMESPACES).collect do |subset_operator|
213
+ SubsetOperator.new(subset_operator)
214
+ end
215
+ end
216
+
217
+ def extract_derivation_operator
218
+ derivation_operators = all_subset_operators.select do |operator|
219
+ ['UNION', 'XPRODUCT'].include?(operator.type)
220
+ end
221
+ raise "More than one derivation operator in data criteria" if derivation_operators.size>1
222
+ derivation_operators.first ? derivation_operators.first.type : nil
223
+ end
224
+
225
+ def extract_subset_operators
226
+ all_subset_operators.select do |operator|
227
+ operator.type != 'UNION' && operator.type != 'XPRODUCT'
228
+ end
229
+ end
230
+
231
+ def extract_specific_or_source
232
+ specific_def = @entry.at_xpath('./*/cda:outboundRelationship[cda:subsetCode/@code="SPECIFIC"]', HQMF2::Document::NAMESPACES)
233
+ source_def = @entry.at_xpath('./*/cda:outboundRelationship[cda:subsetCode/@code="SOURCE"]', HQMF2::Document::NAMESPACES)
234
+ if specific_def
235
+ @source_data_criteria = HQMF2::Utilities.attr_val(specific_def, './cda:observationReference/cda:id/@extension')
236
+ @specific_occurrence_const = HQMF2::Utilities.attr_val(specific_def, './cda:localVariableName/@controlInformationRoot')
237
+ @specific_occurrence = HQMF2::Utilities.attr_val(specific_def, './cda:localVariableName/@controlInformationExtension')
238
+ elsif source_def
239
+ @source_data_criteria = HQMF2::Utilities.attr_val(source_def, './cda:observationReference/cda:id/@extension')
240
+ end
241
+ end
242
+
243
+ def extract_field_values
244
+ fields = {}
245
+ # extract most fields which use the same structure
246
+ @entry.xpath('./*/cda:outboundRelationship[*/cda:code]', HQMF2::Document::NAMESPACES).each do |field|
247
+ code = HQMF2::Utilities.attr_val(field, './*/cda:code/@code')
248
+ code_id = HQMF::DataCriteria::VALUE_FIELDS[code]
249
+ value = DataCriteria.parse_value(field, './*/cda:value')
250
+ fields[code_id] = value
251
+ end
252
+ # special case for facility location which uses a very different structure
253
+ @entry.xpath('./*/cda:outboundRelationship[*/cda:participation]', HQMF2::Document::NAMESPACES).each do |field|
254
+ code = HQMF2::Utilities.attr_val(field, './*/cda:participation/cda:role/@classCode')
255
+ code_id = HQMF::DataCriteria::VALUE_FIELDS[code]
256
+ value = Coded.new(field.at_xpath('./*/cda:participation/cda:role/cda:code', HQMF2::Document::NAMESPACES))
257
+ fields[code_id] = value
258
+ end
259
+ fields
260
+ end
261
+
262
+ def extract_temporal_references
263
+ @entry.xpath('./*/cda:temporallyRelatedInformation', HQMF2::Document::NAMESPACES).collect do |temporal_reference|
264
+ TemporalReference.new(temporal_reference)
265
+ end
266
+ end
267
+
268
+ def extract_value()
269
+ DataCriteria.parse_value(@entry, @value_xpath)
270
+ end
271
+
272
+ def self.parse_value(node, xpath)
273
+ value = nil
274
+ value_def = node.at_xpath(xpath, HQMF2::Document::NAMESPACES)
275
+ if value_def
276
+ value_type_def = value_def.at_xpath('@xsi:type', HQMF2::Document::NAMESPACES)
277
+ if value_type_def
278
+ value_type = value_type_def.value
279
+ case value_type
280
+ when 'TS'
281
+ value = Value.new(value_def)
282
+ when 'IVL_PQ', 'IVL_INT'
283
+ value = Range.new(value_def)
284
+ when 'CD'
285
+ value = Coded.new(value_def)
286
+ when 'ANY'
287
+ value = AnyValue.new()
288
+ else
289
+ raise "Unknown value type [#{value_type}]"
290
+ end
291
+ end
292
+ end
293
+ value
294
+ end
295
+
296
+ def definition_for_demographic
297
+ demographic_type = attr_val('./cda:observationCriteria/cda:code/@code')
298
+ case demographic_type
299
+ when '21112-8'
300
+ "patient_characteristic_birthdate"
301
+ when '424144002'
302
+ "patient_characteristic_age"
303
+ when '263495000'
304
+ "patient_characteristic_gender"
305
+ when '102902016'
306
+ "patient_characteristic_languages"
307
+ when '125680007'
308
+ "patient_characteristic_marital_status"
309
+ when '103579009'
310
+ "patient_characteristic_race"
311
+ else
312
+ raise "Unknown demographic identifier [#{demographic_type}]"
313
+ end
314
+
315
+ end
316
+
317
+ end
318
+
319
+ end
@@ -0,0 +1,165 @@
1
+ module HQMF2
2
+ # Class representing an HQMF document
3
+ class Document
4
+
5
+ include HQMF2::Utilities
6
+ NAMESPACES = {'cda' => 'urn:hl7-org:v3', 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance'}
7
+
8
+ attr_reader :measure_period, :id, :hqmf_set_id, :hqmf_version_number, :populations, :attributes, :source_data_criteria
9
+
10
+ # Create a new HQMF2::Document instance by parsing at file at the supplied path
11
+ # @param [String] path the path to the HQMF document
12
+ def initialize(hqmf_contents)
13
+ @doc = @entry = Document.parse(hqmf_contents)
14
+ @id = attr_val('cda:QualityMeasureDocument/cda:id/@extension')
15
+ @hqmf_set_id = attr_val('cda:QualityMeasureDocument/cda:setId/@extension')
16
+ @hqmf_version_number = attr_val('cda:QualityMeasureDocument/cda:versionNumber/@value').to_i
17
+ measure_period_def = @doc.at_xpath('cda:QualityMeasureDocument/cda:controlVariable/cda:measurePeriod/cda:value', NAMESPACES)
18
+ if measure_period_def
19
+ @measure_period = EffectiveTime.new(measure_period_def)
20
+ end
21
+
22
+ # Extract measure attributes
23
+ @attributes = @doc.xpath('/cda:QualityMeasureDocument/cda:subjectOf/cda:measureAttribute', NAMESPACES).collect do |attribute|
24
+ id = attribute.at_xpath('./cda:id/@extension', NAMESPACES).try(:value)
25
+ code = attribute.at_xpath('./cda:code/@code', NAMESPACES).try(:value)
26
+ name = attribute.at_xpath('./cda:code/cda:displayName/@value', NAMESPACES).try(:value)
27
+ value = attribute.at_xpath('./cda:value/@value', NAMESPACES).try(:value)
28
+ HQMF::Attribute.new(id, code, value, nil, name)
29
+ end
30
+
31
+ # Extract the data criteria
32
+ @data_criteria = []
33
+ @source_data_criteria = []
34
+ @doc.xpath('cda:QualityMeasureDocument/cda:component/cda:dataCriteriaSection/cda:entry', NAMESPACES).each do |entry|
35
+ criteria = DataCriteria.new(entry)
36
+ if criteria.is_source_data_criteria
37
+ @source_data_criteria << criteria
38
+ else
39
+ @data_criteria << criteria
40
+ end
41
+ end
42
+
43
+ # Extract the population criteria and population collections
44
+ @populations = []
45
+ @population_criteria = []
46
+
47
+ population_counters = {}
48
+ ids_by_hqmf_id = {}
49
+
50
+ @doc.xpath('cda:QualityMeasureDocument/cda:component/cda:populationCriteriaSection', NAMESPACES).each_with_index do |population_def, population_index|
51
+ population = {}
52
+
53
+ stratifier_id_def = population_def.at_xpath('cda:templateId/cda:item[@root="'+HQMF::Document::STRATIFIED_POPULATION_TEMPLATE_ID+'"]/@controlInformationRoot', NAMESPACES)
54
+ population['stratification'] = stratifier_id_def.value if stratifier_id_def
55
+
56
+ {
57
+ HQMF::PopulationCriteria::IPP => 'patientPopulationCriteria',
58
+ HQMF::PopulationCriteria::DENOM => 'denominatorCriteria',
59
+ HQMF::PopulationCriteria::NUMER => 'numeratorCriteria',
60
+ HQMF::PopulationCriteria::EXCEP => 'denominatorExceptionCriteria',
61
+ HQMF::PopulationCriteria::DENEX => 'denominatorExclusionCriteria'
62
+ }.each_pair do |criteria_id, criteria_element_name|
63
+ criteria_def = population_def.at_xpath("cda:component[cda:#{criteria_element_name}]", NAMESPACES)
64
+
65
+ if criteria_def
66
+
67
+ criteria = PopulationCriteria.new(criteria_def, self)
68
+
69
+ # check to see if we have an identical population criteria.
70
+ # this can happen since the hqmf 2.0 will export a DENOM, NUMER, etc for each population, even if identical.
71
+ # if we have identical, just re-use it rather than creating DENOM_1, NUMER_1, etc.
72
+ identical = @population_criteria.select {|pc| pc.to_model.base_json.to_json == criteria.to_model.base_json.to_json}
73
+
74
+ if (identical.empty?)
75
+ # this section constructs a human readable id. The first IPP will be IPP, the second will be IPP_1, etc. This allows the populations to be
76
+ # more readable. The alternative would be to have the hqmf ids in the populations, which would work, but is difficult to read the populations.
77
+ if ids_by_hqmf_id["#{criteria.hqmf_id}-#{population['stratification']}"]
78
+ criteria.create_human_readable_id(ids_by_hqmf_id[criteria.hqmf_id])
79
+ else
80
+ if population_counters[criteria_id]
81
+ population_counters[criteria_id] += 1
82
+ criteria.create_human_readable_id("#{criteria_id}_#{population_counters[criteria_id]}")
83
+ else
84
+ population_counters[criteria_id] = 0
85
+ criteria.create_human_readable_id(criteria_id)
86
+ end
87
+ ids_by_hqmf_id["#{criteria.hqmf_id}-#{population['stratification']}"] = criteria.id
88
+ end
89
+
90
+
91
+ @population_criteria << criteria
92
+ population[criteria_id] = criteria.id
93
+ else
94
+ population[criteria_id] = identical.first.id
95
+ end
96
+ end
97
+ end
98
+ id_def = population_def.at_xpath('cda:id/@extension', NAMESPACES)
99
+ population['id'] = id_def ? id_def.value : "Population#{population_index}"
100
+ title_def = population_def.at_xpath('cda:title/@value', NAMESPACES)
101
+ population['title'] = title_def ? title_def.value : "Population #{population_index}"
102
+ @populations << population
103
+ end
104
+ end
105
+
106
+ # Get the title of the measure
107
+ # @return [String] the title
108
+ def title
109
+ @doc.at_xpath('cda:QualityMeasureDocument/cda:title/@value', NAMESPACES).inner_text
110
+ end
111
+
112
+ # Get the description of the measure
113
+ # @return [String] the description
114
+ def description
115
+ description = @doc.at_xpath('cda:QualityMeasureDocument/cda:text/@value', NAMESPACES)
116
+ description==nil ? '' : description.inner_text
117
+ end
118
+
119
+ # Get all the population criteria defined by the measure
120
+ # @return [Array] an array of HQMF2::PopulationCriteria
121
+ def all_population_criteria
122
+ @population_criteria
123
+ end
124
+
125
+ # Get a specific population criteria by id.
126
+ # @param [String] id the population identifier
127
+ # @return [HQMF2::PopulationCriteria] the matching criteria, raises an Exception if not found
128
+ def population_criteria(id)
129
+ find(@population_criteria, :id, id)
130
+ end
131
+
132
+ # Get all the data criteria defined by the measure
133
+ # @return [Array] an array of HQMF2::DataCriteria describing the data elements used by the measure
134
+ def all_data_criteria
135
+ @data_criteria
136
+ end
137
+
138
+ # Get a specific data criteria by id.
139
+ # @param [String] id the data criteria identifier
140
+ # @return [HQMF2::DataCriteria] the matching data criteria, raises an Exception if not found
141
+ def data_criteria(id)
142
+ find(@data_criteria, :id, id)
143
+ end
144
+
145
+ # Parse an XML document at the supplied path
146
+ # @return [Nokogiri::XML::Document]
147
+ def self.parse(hqmf_contents)
148
+ doc = Nokogiri::XML(hqmf_contents)
149
+ doc
150
+ end
151
+
152
+ def to_model
153
+ dcs = all_data_criteria.collect {|dc| dc.to_model}
154
+ pcs = all_population_criteria.collect {|pc| pc.to_model}
155
+ sdc = source_data_criteria.collect{|dc| dc.to_model}
156
+ HQMF::Document.new(id, id, hqmf_set_id, hqmf_version_number, title, description, pcs, dcs, sdc, attributes, measure_period.to_model, populations)
157
+ end
158
+
159
+ private
160
+
161
+ def find(collection, attribute, value)
162
+ collection.find {|e| e.send(attribute)==value}
163
+ end
164
+ end
165
+ end