openehr 2.1.0 → 2.3.1
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.
- checksums.yaml +4 -4
- data/README.rdoc +19 -6
- data/lib/openehr/am/openehr_profile/data_types/text.rb +21 -0
- data/lib/openehr/aql/engine/contains_resolver.rb +98 -7
- data/lib/openehr/aql/engine/dataset.rb +3 -1
- data/lib/openehr/aql/engine/predicate_evaluator.rb +70 -3
- data/lib/openehr/aql/engine.rb +45 -12
- data/lib/openehr/parser/opt_parser.rb +12 -425
- data/lib/openehr/parser/xml_archetype_parser.rb +255 -0
- data/lib/openehr/parser/xml_constraint_parsing.rb +275 -0
- data/lib/openehr/parser/xml_domain_type_parsing.rb +142 -0
- data/lib/openehr/parser/xml_primitive_parsing.rb +145 -0
- data/lib/openehr/parser.rb +1 -0
- data/lib/openehr/rm/common/generic.rb +4 -7
- data/lib/openehr/rm/composition/content/entry.rb +4 -1
- data/lib/openehr/rm/data_structures/item_structure/representation.rb +12 -2
- data/lib/openehr/rm/data_types/basic.rb +8 -9
- data/lib/openehr/rm/data_types/encapsulated.rb +16 -0
- data/lib/openehr/rm/data_types/quantity/date_time.rb +168 -0
- data/lib/openehr/rm/data_types/quantity.rb +64 -9
- data/lib/openehr/rm/ehr.rb +6 -6
- data/lib/openehr/rm/factory.rb +4 -0
- data/lib/openehr/serializer/adl_serializer.rb +151 -14
- data/lib/openehr/serializer/xml_serializer.rb +345 -99
- data/lib/openehr/version.rb +1 -1
- metadata +6 -2
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
require 'nokogiri'
|
|
2
|
+
require_relative 'xml_constraint_parsing'
|
|
3
|
+
require_relative 'xml_primitive_parsing'
|
|
4
|
+
require_relative 'xml_domain_type_parsing'
|
|
2
5
|
|
|
3
6
|
module OpenEHR
|
|
4
7
|
module Parser
|
|
5
8
|
class OPTParser < ::OpenEHR::Parser::Base
|
|
9
|
+
include XMLConstraintParsing
|
|
10
|
+
include XMLPrimitiveParsing
|
|
11
|
+
include XMLDomainTypeParsing
|
|
12
|
+
|
|
6
13
|
TEMPLATE_LANGUAGE_CODE_PATH =
|
|
7
14
|
'/template/language/code_string'
|
|
8
15
|
TEMPLATE_LANGUAGE_TERM_ID_PATH =
|
|
9
|
-
'/template/language/terminology_id/value'
|
|
16
|
+
'/template/language/terminology_id/value'
|
|
10
17
|
TEMPLATE_ID_PATH = '/template/template_id/value'
|
|
11
18
|
UID_PATH = '/template/uid/value'
|
|
12
19
|
CONCEPT_PATH = '/template/concept'
|
|
@@ -35,10 +42,10 @@ module OpenEHR
|
|
|
35
42
|
def parse
|
|
36
43
|
@opt = Nokogiri::XML::Document.parse(File.open(@filename))
|
|
37
44
|
@opt.remove_namespaces!
|
|
38
|
-
|
|
45
|
+
|
|
39
46
|
uid = build_uid
|
|
40
47
|
defs = definition
|
|
41
|
-
|
|
48
|
+
|
|
42
49
|
# Create operational template with archetype-compatible parameters
|
|
43
50
|
OpenEHR::AM::Template::OperationalTemplate.new(
|
|
44
51
|
uid: uid,
|
|
@@ -119,7 +126,7 @@ module OpenEHR
|
|
|
119
126
|
# Create a basic ontology for the template using the main concept
|
|
120
127
|
concept_code = 'at0000'
|
|
121
128
|
original_lang = language
|
|
122
|
-
|
|
129
|
+
|
|
123
130
|
term_definitions = {
|
|
124
131
|
original_lang.code_string => [
|
|
125
132
|
OpenEHR::AM::Archetype::Terminology::ArchetypeTerm.new(
|
|
@@ -131,7 +138,7 @@ module OpenEHR
|
|
|
131
138
|
)
|
|
132
139
|
]
|
|
133
140
|
}
|
|
134
|
-
|
|
141
|
+
|
|
135
142
|
OpenEHR::AM::Archetype::Terminology::ArchetypeTerminology.new(
|
|
136
143
|
concept_code: concept_code,
|
|
137
144
|
original_language: original_lang,
|
|
@@ -160,418 +167,6 @@ module OpenEHR
|
|
|
160
167
|
{ language.code_string => term_items }
|
|
161
168
|
end
|
|
162
169
|
|
|
163
|
-
def c_archetype_root(xml, node = Node.new)
|
|
164
|
-
rm_type_name = text_on_path(xml, './rm_type_name')
|
|
165
|
-
id = text_on_path(xml, './node_id')
|
|
166
|
-
node.id = id unless id.nil? or id.empty?
|
|
167
|
-
occurrences = occurrences(xml.xpath('./occurrences'))
|
|
168
|
-
archetype_id = OpenEHR::RM::Support::Identification::ArchetypeID.new(value: text_on_path(xml, './archetype_id/value'))
|
|
169
|
-
if node.root? or node.id.nil?
|
|
170
|
-
node.path = "/"
|
|
171
|
-
# else
|
|
172
|
-
# node.path += "/" #"/[#{archetype_id.value}]"
|
|
173
|
-
end
|
|
174
|
-
component_terminologies(archetype_id, xml)
|
|
175
|
-
OpenEHR::AM::Archetype::ConstraintModel::CArchetypeRoot.new(rm_type_name: rm_type_name, node_id: node.id, path: node.path, occurrences: occurrences, archetype_id: archetype_id, attributes: attributes(xml.xpath('./attributes'), node))
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def c_complex_object(xml, node)
|
|
179
|
-
rm_type_name = xml.xpath('./rm_type_name').text
|
|
180
|
-
node_id = xml.xpath('./node_id').text
|
|
181
|
-
unless node_id.nil? or node_id.empty?
|
|
182
|
-
node.id = node_id
|
|
183
|
-
node.path = "#{node.path}[#{node.id}]"
|
|
184
|
-
end
|
|
185
|
-
OpenEHR::AM::Archetype::ConstraintModel::CComplexObject.new(rm_type_name: rm_type_name, node_id: node.id, path: node.path, occurrences: occurrences(xml.xpath('./occurrences')), attributes: attributes(xml.xpath('./attributes'), node))
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def attributes(attributes_xml, node)
|
|
189
|
-
attributes_xml.map do |attr|
|
|
190
|
-
rm_attribute_name = attr.at('rm_attribute_name').text
|
|
191
|
-
if node.root?
|
|
192
|
-
path = "/#{rm_attribute_name}"
|
|
193
|
-
# elsif node.id
|
|
194
|
-
# path = "#{node.path}[#{node.id}]/#{rm_attribute_name}"
|
|
195
|
-
else
|
|
196
|
-
path = "#{node.path}/#{rm_attribute_name}"
|
|
197
|
-
end
|
|
198
|
-
child_node = Node.new(node)
|
|
199
|
-
child_node.path = path
|
|
200
|
-
child_node.id = node.id
|
|
201
|
-
send attr.attributes['type'].text.downcase, attr, child_node
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def children(children_xml, node)
|
|
206
|
-
children_xml.map do |child|
|
|
207
|
-
send child.attributes['type'].text.downcase, child, node
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def c_single_attribute(attr_xml, node)
|
|
212
|
-
rm_attribute_name = attr_xml.at('rm_attribute_name').text
|
|
213
|
-
existence = occurrences(attr_xml.at('existence'))
|
|
214
|
-
OpenEHR::AM::Archetype::ConstraintModel::CSingleAttribute.new(rm_attribute_name: rm_attribute_name, existence: existence, path: node.path, children: children(attr_xml.xpath('./children'), node))
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def c_multiple_attribute(attr_xml, node)
|
|
218
|
-
rm_attribute_name = attr_xml.at('rm_attribute_name').text
|
|
219
|
-
existence = occurrences(attr_xml.at('existence'))
|
|
220
|
-
OpenEHR::AM::Archetype::ConstraintModel::CMultipleAttribute.new(rm_attribute_name: rm_attribute_name, existence: existence, path: node.path, cardinality: cardinality(attr_xml), children: children(attr_xml.xpath('./children'), node))
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def c_code_phrase(attr_xml, node)
|
|
224
|
-
terminology_id_node = attr_xml.at('terminology_id/value')
|
|
225
|
-
terminology_id = terminology_id_node ? OpenEHR::RM::Support::Identification::TerminologyID.new(value: terminology_id_node.text.strip) : nil
|
|
226
|
-
|
|
227
|
-
code_list_nodes = attr_xml.xpath('code_list')
|
|
228
|
-
code_list = code_list_nodes.map { |code_node| code_node.text.strip }
|
|
229
|
-
code_list = [code_list.first] if code_list.size == 1 && code_list.first.empty?
|
|
230
|
-
|
|
231
|
-
occurrences_node = attr_xml.at('occurrences')
|
|
232
|
-
occurrences_obj = occurrences_node ? occurrences(occurrences_node) : nil
|
|
233
|
-
|
|
234
|
-
OpenEHR::AM::OpenEHRProfile::DataTypes::Text::CCodePhrase.new(
|
|
235
|
-
terminology_id: terminology_id,
|
|
236
|
-
code_list: code_list,
|
|
237
|
-
path: node.path,
|
|
238
|
-
occurrences: occurrences_obj,
|
|
239
|
-
rm_type_name: 'CODE_PHRASE'
|
|
240
|
-
)
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def archetype_slot(attr_xml,node)
|
|
244
|
-
path = node.path
|
|
245
|
-
node.id = attr_xml.at('node_id').text
|
|
246
|
-
rm_type_name = attr_xml.at('rm_type_name').text
|
|
247
|
-
occurrences = occurrences(attr_xml.at('occurrences'))
|
|
248
|
-
includes_leaf = attr_xml.at('includes')
|
|
249
|
-
includes = assertions(includes_leaf.children, node) if includes_leaf
|
|
250
|
-
excludes_leaf = attr_xml.at('excludes')
|
|
251
|
-
excludes = assertions(excludes_leaf.children, node) if excludes_leaf
|
|
252
|
-
OpenEHR::AM::Archetype::ConstraintModel::ArchetypeSlot.new(path: path, node_id: node.id, rm_type_name: rm_type_name, occurrences: occurrences, includes: includes, excludes: excludes)
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def occurrences(occurrence_xml)
|
|
256
|
-
return nil if occurrence_xml.nil?
|
|
257
|
-
|
|
258
|
-
lower_node = occurrence_xml.at('lower')
|
|
259
|
-
upper_node = occurrence_xml.at('upper')
|
|
260
|
-
lower_included_node = occurrence_xml.at('lower_included')
|
|
261
|
-
upper_included_node = occurrence_xml.at('upper_included')
|
|
262
|
-
lower_unbounded_node = occurrence_xml.at('lower_unbounded')
|
|
263
|
-
upper_unbounded_node = occurrence_xml.at('upper_unbounded')
|
|
264
|
-
|
|
265
|
-
lower = lower_node ? lower_node.text.to_i : nil
|
|
266
|
-
upper = upper_node ? upper_node.text.to_i : nil
|
|
267
|
-
lower_included = lower_included_node ? to_bool(lower_included_node.text) : (lower.nil? ? nil : true)
|
|
268
|
-
upper_included = upper_included_node ? to_bool(upper_included_node.text) : (upper.nil? ? nil : true)
|
|
269
|
-
lower_unbounded = lower_unbounded_node ? to_bool(lower_unbounded_node.text) : false
|
|
270
|
-
upper_unbounded = upper_unbounded_node ? to_bool(upper_unbounded_node.text) : false
|
|
271
|
-
|
|
272
|
-
# An occurrences element with none of its children present carries no
|
|
273
|
-
# constraint at all; Interval requires at least one bound, so treat
|
|
274
|
-
# this as "no occurrences data" rather than raising.
|
|
275
|
-
return nil if lower.nil? && upper.nil? && !lower_unbounded && !upper_unbounded
|
|
276
|
-
|
|
277
|
-
# Handle unbounded intervals properly
|
|
278
|
-
if upper_unbounded || upper.nil?
|
|
279
|
-
upper = nil
|
|
280
|
-
upper_included = nil
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
if lower_unbounded || lower.nil?
|
|
284
|
-
lower = nil
|
|
285
|
-
lower_included = nil
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
OpenEHR::AssumedLibraryTypes::Interval.new(
|
|
289
|
-
lower: lower,
|
|
290
|
-
upper: upper,
|
|
291
|
-
lower_included: lower_included,
|
|
292
|
-
upper_included: upper_included
|
|
293
|
-
)
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
def cardinality(xml)
|
|
297
|
-
return nil if xml.nil?
|
|
298
|
-
|
|
299
|
-
order_node = xml.at('is_ordered')
|
|
300
|
-
unique_node = xml.at('is_unique')
|
|
301
|
-
interval_node = xml.at('interval')
|
|
302
|
-
|
|
303
|
-
# No cardinality sub-elements at all means no cardinality data.
|
|
304
|
-
return nil if order_node.nil? && unique_node.nil? && interval_node.nil?
|
|
305
|
-
|
|
306
|
-
order = order_node ? to_bool(order_node.text) : false
|
|
307
|
-
unique = unique_node ? to_bool(unique_node.text) : false
|
|
308
|
-
interval = interval_node ? occurrences(interval_node) : nil
|
|
309
|
-
|
|
310
|
-
OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new(
|
|
311
|
-
is_ordered: order,
|
|
312
|
-
is_unique: unique,
|
|
313
|
-
interval: interval
|
|
314
|
-
)
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
def archetype_internal_ref(attr_xml, node)
|
|
318
|
-
rm_type_name = attr_xml.at('rm_type_name').text
|
|
319
|
-
target_path = attr_xml.at('target_path').text
|
|
320
|
-
occurrences = occurrences(attr_xml.at('occurrences'))
|
|
321
|
-
OpenEHR::AM::Archetype::ConstraintModel::ArchetypeInternalRef.new(rm_type_name: rm_type_name, occurrences: occurrences, target_path: target_path)
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
# No .opt fixture in this gem's corpus uses a C_DV_STATE (state
|
|
325
|
-
# machine) constraint, so its actual OPT XML shape is unverified;
|
|
326
|
-
# raising a clear, documented error here is safer than guessing
|
|
327
|
-
# at element names and risking a silently wrong StateMachine.
|
|
328
|
-
def c_dv_state(_attr_xml, _node)
|
|
329
|
-
raise NotImplementedError, 'OPTParser does not yet support C_DV_STATE (state machine) constraints'
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
def constraint_ref(attr_xml, node)
|
|
333
|
-
rm_type_name = attr_xml.at('rm_type_name').text
|
|
334
|
-
reference = attr_xml.at('reference').text
|
|
335
|
-
occurrences = occurrences(attr_xml.at('occurrences'))
|
|
336
|
-
OpenEHR::AM::Archetype::ConstraintModel::ConstraintRef.new(rm_type_name: rm_type_name, occurrences: occurrences, reference: reference)
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
def assertions(attr_xml, node)
|
|
340
|
-
string_expression = attr_xml.at('string_expression')
|
|
341
|
-
string_expression = string_expression.nil? ? nil : string_expression.text
|
|
342
|
-
expression_leaf = attr_xml.at 'expression'
|
|
343
|
-
expression = send expression_leaf.attributes['type'].text.downcase, expression_leaf
|
|
344
|
-
[OpenEHR::AM::Archetype::Assertion::Assertion.new(expression: expression, string_expression: string_expression)]
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
def expr_binary_operator(attr_xml)
|
|
348
|
-
type = attr_xml.at('type').text
|
|
349
|
-
operator = OpenEHR::AM::Archetype::Assertion::OperatorKind.new(value: attr_xml.at('operator').text.to_i)
|
|
350
|
-
|
|
351
|
-
precedence_overridden = attr_xml.at('precedence_overridden').text == 'true' ? true : false
|
|
352
|
-
right_operand_leaf = attr_xml.at 'right_operand'
|
|
353
|
-
right_operand = send right_operand_leaf.attributes['type'].text.downcase, right_operand_leaf
|
|
354
|
-
left_operand_leaf = attr_xml.at 'left_operand'
|
|
355
|
-
left_operand = send left_operand_leaf.attributes['type'].text.downcase, left_operand_leaf
|
|
356
|
-
OpenEHR::AM::Archetype::Assertion::ExprBinaryOperator.new(type: type, operator: operator, precedence_overridden: precedence_overridden, right_operand: right_operand, left_operand: left_operand)
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
def expr_leaf(attr_xml)
|
|
360
|
-
type = attr_xml.at('type').text
|
|
361
|
-
item_leaf = attr_xml.at('item')
|
|
362
|
-
item = send type.downcase, item_leaf
|
|
363
|
-
reference_type = attr_xml.at('reference_type').text
|
|
364
|
-
OpenEHR::AM::Archetype::Assertion::ExprLeaf.new(type: type, item: item, reference_type: reference_type)
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
def c_primitive_object(attr_xml, node)
|
|
368
|
-
rm_type_name = attr_xml.at('rm_type_name').text
|
|
369
|
-
occurrences = occurrences(attr_xml.at('occurrences'))
|
|
370
|
-
item = send attr_xml.at('item')['type'].downcase, attr_xml.at('item')
|
|
371
|
-
OpenEHR::AM::Archetype::ConstraintModel::CPrimitiveObject.new(rm_type_name: rm_type_name, occurrences: occurrences, node_id: node.id, item: item)
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
def c_string(attr_xml)
|
|
375
|
-
if attr_xml.at('pattern')
|
|
376
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new(pattern: attr_xml.at('pattern').text)
|
|
377
|
-
else
|
|
378
|
-
list = attr_xml.xpath('.//list').map do |str|
|
|
379
|
-
str.text
|
|
380
|
-
end
|
|
381
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new(list: list)
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
def c_dv_quantity(attr_xml, node)
|
|
386
|
-
rm_type_name = attr_xml.at('rm_type_name').text
|
|
387
|
-
occurrences = occurrences(attr_xml.at('occurrences'))
|
|
388
|
-
property = property_code_phrase(attr_xml.at('property'))
|
|
389
|
-
list = attr_xml.xpath('.//list').map do |element|
|
|
390
|
-
units = element.at('units').text if element.at('units')
|
|
391
|
-
magnitude = occurrences(element.at('magnitude')) if element.at('magnitude')
|
|
392
|
-
precision = occurrences(element.at('precision')) if element.at('precision')
|
|
393
|
-
OpenEHR::AM::OpenEHRProfile::DataTypes::Quantity::CQuantityItem.new(magnitude: magnitude, precision: precision, units: units)
|
|
394
|
-
end
|
|
395
|
-
OpenEHR::AM::OpenEHRProfile::DataTypes::Quantity::CDvQuantity.new(rm_type_name: rm_type_name, occurrences: occurrences, list: list, property: property)
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
# The <property> element is optional in real templates; return nil rather
|
|
399
|
-
# than dereferencing missing terminology/code nodes.
|
|
400
|
-
def property_code_phrase(property_xml)
|
|
401
|
-
return nil if property_xml.nil?
|
|
402
|
-
terminology_node = property_xml.at('terminology_id/value')
|
|
403
|
-
code_node = property_xml.at('code_string')
|
|
404
|
-
return nil if terminology_node.nil? || code_node.nil?
|
|
405
|
-
terminology_id = OpenEHR::RM::Support::Identification::TerminologyID.new(value: terminology_node.text)
|
|
406
|
-
OpenEHR::RM::DataTypes::Text::CodePhrase.new(terminology_id: terminology_id, code_string: code_node.text)
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
def c_dv_ordinal(attr_xml, node)
|
|
410
|
-
rm_type_name = attr_xml.at('rm_type_name').text
|
|
411
|
-
occurrences = occurrences(attr_xml.at('occurrences'))
|
|
412
|
-
list = attr_xml.xpath('list').map { |element| dv_ordinal_item(element) }.compact
|
|
413
|
-
OpenEHR::AM::OpenEHRProfile::DataTypes::Quantity::CDvOrdinal.new(rm_type_name: rm_type_name, occurrences: occurrences, list: list)
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
# DV_ORDINAL.symbol is spec'd as DV_CODED_TEXT; the OPT XML only
|
|
417
|
-
# carries a defining_code (terminology_id + code_string), so the
|
|
418
|
-
# DvCodedText's own value is set to that same code_string (there
|
|
419
|
-
# is no separate display text in this element).
|
|
420
|
-
def dv_ordinal_item(element)
|
|
421
|
-
value_node = element.at('value')
|
|
422
|
-
return nil unless value_node && !value_node.text.empty?
|
|
423
|
-
|
|
424
|
-
code_phrase = property_code_phrase(element.at('symbol/defining_code'))
|
|
425
|
-
return nil if code_phrase.nil?
|
|
426
|
-
|
|
427
|
-
symbol = OpenEHR::RM::DataTypes::Text::DvCodedText.new(value: code_phrase.code_string, defining_code: code_phrase)
|
|
428
|
-
OpenEHR::RM::DataTypes::Quantity::DvOrdinal.new(value: value_node.text.to_i, symbol: symbol)
|
|
429
|
-
end
|
|
430
|
-
|
|
431
|
-
def c_dv_scale(attr_xml, node)
|
|
432
|
-
rm_type_name = attr_xml.at('rm_type_name').text
|
|
433
|
-
occurrences = occurrences(attr_xml.at('occurrences'))
|
|
434
|
-
list = attr_xml.xpath('list').map { |element| dv_scale_item(element) }.compact
|
|
435
|
-
OpenEHR::AM::OpenEHRProfile::DataTypes::Quantity::CDvScale.new(rm_type_name: rm_type_name, occurrences: occurrences, list: list)
|
|
436
|
-
end
|
|
437
|
-
|
|
438
|
-
# Same XML shape as C_DV_ORDINAL's list items, but DV_SCALE.value
|
|
439
|
-
# is Real rather than Integer.
|
|
440
|
-
def dv_scale_item(element)
|
|
441
|
-
value_node = element.at('value')
|
|
442
|
-
return nil unless value_node && !value_node.text.empty?
|
|
443
|
-
|
|
444
|
-
code_phrase = property_code_phrase(element.at('symbol/defining_code'))
|
|
445
|
-
return nil if code_phrase.nil?
|
|
446
|
-
|
|
447
|
-
symbol = OpenEHR::RM::DataTypes::Text::DvCodedText.new(value: code_phrase.code_string, defining_code: code_phrase)
|
|
448
|
-
OpenEHR::RM::DataTypes::Quantity::DvScale.new(value: value_node.text.to_f, symbol: symbol)
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
def c_date(xml)
|
|
452
|
-
pattern = xml.at('pattern')
|
|
453
|
-
range = xml.at('range')
|
|
454
|
-
if pattern
|
|
455
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDate.new(pattern: pattern.text)
|
|
456
|
-
elsif range
|
|
457
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDate.new(range: occurrences(range))
|
|
458
|
-
else
|
|
459
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDate.new
|
|
460
|
-
end
|
|
461
|
-
end
|
|
462
|
-
|
|
463
|
-
def c_date_time(xml)
|
|
464
|
-
pattern = xml.at('pattern')
|
|
465
|
-
range = xml.at('range')
|
|
466
|
-
if pattern
|
|
467
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDateTime.new(pattern: pattern.text)
|
|
468
|
-
elsif range
|
|
469
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDateTime.new(range: occurrences(range))
|
|
470
|
-
else
|
|
471
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDateTime.new
|
|
472
|
-
end
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
def c_integer(xml)
|
|
476
|
-
range = xml.at('range')
|
|
477
|
-
list = xml.xpath('list')
|
|
478
|
-
if range
|
|
479
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CInteger.new(range: occurrences(range))
|
|
480
|
-
elsif !list.empty?
|
|
481
|
-
list_values = list.map { |item| item.text.to_i }
|
|
482
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CInteger.new(list: list_values)
|
|
483
|
-
else
|
|
484
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CInteger.new
|
|
485
|
-
end
|
|
486
|
-
end
|
|
487
|
-
|
|
488
|
-
def c_real(xml)
|
|
489
|
-
range = xml.at('range')
|
|
490
|
-
list = xml.xpath('list')
|
|
491
|
-
if range
|
|
492
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CReal.new(range: occurrences(range))
|
|
493
|
-
elsif !list.empty?
|
|
494
|
-
list_values = list.map { |item| item.text.to_f }
|
|
495
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CReal.new(list: list_values)
|
|
496
|
-
else
|
|
497
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CReal.new
|
|
498
|
-
end
|
|
499
|
-
end
|
|
500
|
-
|
|
501
|
-
def c_duration(xml)
|
|
502
|
-
pattern = xml.at('pattern')
|
|
503
|
-
range_xml = xml.at('range')
|
|
504
|
-
list = xml.xpath('list')
|
|
505
|
-
if pattern
|
|
506
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDuration.new(pattern: pattern.text)
|
|
507
|
-
elsif range_xml
|
|
508
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDuration.new(range: duration_range(range_xml))
|
|
509
|
-
elsif !list.empty?
|
|
510
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDuration.new(list: list.map(&:text))
|
|
511
|
-
else
|
|
512
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CDuration.new
|
|
513
|
-
end
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
# A C_DURATION range's bounds are ISO8601 duration strings (e.g.
|
|
517
|
-
# PT24H), not plain numbers, so occurrences() (built for numeric
|
|
518
|
-
# Interval bounds) doesn't apply here; wrap each bound as a
|
|
519
|
-
# DV_DURATION instead, matching what CDuration#valid_value?
|
|
520
|
-
# already expects its range bounds to be.
|
|
521
|
-
def duration_range(range_xml)
|
|
522
|
-
lower = duration_bound(range_xml.at('lower'), range_xml.at('lower_unbounded'))
|
|
523
|
-
upper = duration_bound(range_xml.at('upper'), range_xml.at('upper_unbounded'))
|
|
524
|
-
return nil if lower.nil? && upper.nil?
|
|
525
|
-
|
|
526
|
-
OpenEHR::AssumedLibraryTypes::Interval.new(
|
|
527
|
-
lower: lower, upper: upper,
|
|
528
|
-
lower_included: lower.nil? ? nil : bool_node(range_xml.at('lower_included'), true),
|
|
529
|
-
upper_included: upper.nil? ? nil : bool_node(range_xml.at('upper_included'), true))
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
def duration_bound(value_node, unbounded_node)
|
|
533
|
-
return nil if bool_node(unbounded_node, false)
|
|
534
|
-
return nil if value_node.nil? || value_node.text.empty?
|
|
535
|
-
|
|
536
|
-
OpenEHR::RM::DataTypes::Quantity::DateTime::DvDuration.new(value: value_node.text)
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
def bool_node(node, default)
|
|
540
|
-
node ? to_bool(node.text) : default
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
def c_time(xml)
|
|
544
|
-
pattern = xml.at('pattern')
|
|
545
|
-
range = xml.at('range')
|
|
546
|
-
if pattern
|
|
547
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CTime.new(pattern: pattern.text)
|
|
548
|
-
elsif range
|
|
549
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CTime.new(range: occurrences(range))
|
|
550
|
-
else
|
|
551
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CTime.new
|
|
552
|
-
end
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
def c_boolean(xml)
|
|
556
|
-
true_valid = xml.at('true_valid')
|
|
557
|
-
false_valid = xml.at('false_valid')
|
|
558
|
-
assumed_value = xml.at('assumed_value')
|
|
559
|
-
|
|
560
|
-
true_valid_value = true_valid ? to_bool(true_valid.text) : nil
|
|
561
|
-
false_valid_value = false_valid ? to_bool(false_valid.text) : nil
|
|
562
|
-
assumed_value_value = assumed_value ? to_bool(assumed_value.text) : nil
|
|
563
|
-
|
|
564
|
-
OpenEHR::AM::Archetype::ConstraintModel::Primitive::CBoolean.new(
|
|
565
|
-
true_valid: true_valid_value,
|
|
566
|
-
false_valid: false_valid_value,
|
|
567
|
-
assumed_value: assumed_value_value
|
|
568
|
-
)
|
|
569
|
-
end
|
|
570
|
-
|
|
571
|
-
def string(attr_xml)
|
|
572
|
-
attr_xml.text
|
|
573
|
-
end
|
|
574
|
-
|
|
575
170
|
def empty_then_nil(val)
|
|
576
171
|
if val.empty?
|
|
577
172
|
return nil
|
|
@@ -583,14 +178,6 @@ module OpenEHR
|
|
|
583
178
|
def text_on_path(xml, path)
|
|
584
179
|
xml.xpath(path).text
|
|
585
180
|
end
|
|
586
|
-
|
|
587
|
-
def to_bool(str)
|
|
588
|
-
return nil if str.nil?
|
|
589
|
-
str = str.text if str.respond_to?(:text)
|
|
590
|
-
return true if /true/i =~ str.to_s
|
|
591
|
-
return false if /false/i =~ str.to_s
|
|
592
|
-
nil
|
|
593
|
-
end
|
|
594
181
|
end
|
|
595
182
|
end
|
|
596
183
|
end
|