openehr 1.3.0 → 2.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.
- checksums.yaml +4 -4
- data/README.rdoc +93 -12
- data/lib/openehr/am/archetype/constraint_model/primitive.rb +204 -6
- data/lib/openehr/am/archetype/constraint_model.rb +228 -4
- data/lib/openehr/am/archetype/ontology.rb +2 -2
- data/lib/openehr/am/archetype.rb +101 -2
- data/lib/openehr/am/openehr_profile/data_types/basic.rb +28 -0
- data/lib/openehr/am/openehr_profile/data_types/quantity.rb +88 -0
- data/lib/openehr/am/openehr_profile/data_types/text.rb +23 -0
- data/lib/openehr/am/template.rb +25 -3
- data/lib/openehr/aql/engine/binding.rb +13 -0
- data/lib/openehr/aql/engine/contains_resolver.rb +161 -0
- data/lib/openehr/aql/engine/dataset.rb +122 -0
- data/lib/openehr/aql/engine/path_evaluator.rb +137 -0
- data/lib/openehr/aql/engine/predicate_evaluator.rb +65 -0
- data/lib/openehr/aql/engine.rb +119 -0
- data/lib/openehr/aql/errors.rb +27 -0
- data/lib/openehr/aql/lexer.rb +295 -0
- data/lib/openehr/aql/model/containment.rb +45 -0
- data/lib/openehr/aql/model/from_clause.rb +35 -0
- data/lib/openehr/aql/model/function_call.rb +56 -0
- data/lib/openehr/aql/model/identified_path.rb +20 -0
- data/lib/openehr/aql/model/literal.rb +15 -0
- data/lib/openehr/aql/model/object_path.rb +34 -0
- data/lib/openehr/aql/model/order_by_and_limit.rb +50 -0
- data/lib/openehr/aql/model/predicate.rb +84 -0
- data/lib/openehr/aql/model/query.rb +24 -0
- data/lib/openehr/aql/model/select_clause.rb +29 -0
- data/lib/openehr/aql/model/where_clause.rb +105 -0
- data/lib/openehr/aql/model.rb +14 -0
- data/lib/openehr/aql/parser.rb +484 -0
- data/lib/openehr/aql/result_set.rb +54 -0
- data/lib/openehr/aql.rb +28 -0
- data/lib/openehr/assumed_library_types.rb +68 -17
- data/lib/openehr/parser/adl_grammar.tt +29 -13
- data/lib/openehr/parser/adl_parser.rb +18 -4
- data/lib/openehr/parser/archetype_validator.rb +126 -0
- data/lib/openehr/parser/exception.rb +13 -0
- data/lib/openehr/parser/opt_parser.rb +162 -9
- data/lib/openehr/parser.rb +2 -0
- data/lib/openehr/path.rb +195 -0
- data/lib/openehr/rm/common/archetyped.rb +116 -6
- data/lib/openehr/rm/common/change_control.rb +3 -8
- data/lib/openehr/rm/common/directory.rb +4 -0
- data/lib/openehr/rm/common/generic.rb +24 -10
- data/lib/openehr/rm/composition/content/entry.rb +24 -5
- data/lib/openehr/rm/composition/content/navigation.rb +2 -1
- data/lib/openehr/rm/composition.rb +19 -2
- data/lib/openehr/rm/data_structures/history.rb +3 -0
- data/lib/openehr/rm/data_structures/item_structure/representation.rb +13 -9
- data/lib/openehr/rm/data_structures/item_structure.rb +28 -15
- data/lib/openehr/rm/data_types/encapsulated.rb +23 -3
- data/lib/openehr/rm/data_types/quantity/date_time.rb +9 -1
- data/lib/openehr/rm/data_types/quantity.rb +66 -14
- data/lib/openehr/rm/data_types/text.rb +8 -0
- data/lib/openehr/rm/data_types/time_specification.rb +5 -4
- data/lib/openehr/rm/demographic.rb +4 -3
- data/lib/openehr/rm/ehr.rb +20 -1
- data/lib/openehr/rm/factory.rb +234 -6
- data/lib/openehr/rm/integration.rb +1 -0
- data/lib/openehr/rm/support/identification.rb +37 -8
- data/lib/openehr/rm/support/measurement.rb +32 -0
- data/lib/openehr/rm/type_name.rb +90 -0
- data/lib/openehr/rm.rb +3 -0
- data/lib/openehr/serializer/adl_serializer.rb +335 -0
- data/lib/openehr/serializer/base.rb +20 -0
- data/lib/openehr/serializer/opt_serializer.rb +49 -0
- data/lib/openehr/serializer/rm_json_serializer.rb +62 -0
- data/lib/openehr/serializer/xml_serializer.rb +260 -0
- data/lib/openehr/serializer.rb +5 -291
- data/lib/openehr/terminology_service.rb +44 -0
- data/lib/openehr/version.rb +1 -1
- data/lib/openehr.rb +5 -2
- metadata +35 -7
- data/lib/openehr/parser/validator.rb +0 -18
- data/lib/openehr/parser/xml_parser.rb +0 -13
- data/lib/openehr/rm/data_types/charset_extract.rb +0 -24
- data/lib/openehr/writer.rb +0 -12
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
require 'rexml/document'
|
|
2
|
+
require 'builder'
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module OpenEHR
|
|
6
|
+
module Serializer
|
|
7
|
+
class XMLSerializer < BaseSerializer
|
|
8
|
+
def header
|
|
9
|
+
header = ''
|
|
10
|
+
xml = Builder::XmlMarkup.new(:indent => 2, :target => header)
|
|
11
|
+
xml.archetype_id do
|
|
12
|
+
xml.value @archetype.archetype_id.value
|
|
13
|
+
end
|
|
14
|
+
xml.concept @archetype.concept
|
|
15
|
+
xml.original_language do
|
|
16
|
+
xml.terminology_id do
|
|
17
|
+
xml.value @archetype.original_language.terminology_id.value
|
|
18
|
+
end
|
|
19
|
+
xml.code_string @archetype.original_language.code_string
|
|
20
|
+
end
|
|
21
|
+
return header
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def description
|
|
25
|
+
desc = ''
|
|
26
|
+
xml = Builder::XmlMarkup.new(:indent => 2, :target => desc)
|
|
27
|
+
ad = @archetype.description
|
|
28
|
+
if ad
|
|
29
|
+
xml.description do
|
|
30
|
+
ad.original_author.each do |key,value|
|
|
31
|
+
xml.original_author(value,"id"=>key)
|
|
32
|
+
end
|
|
33
|
+
if ad.other_contributors
|
|
34
|
+
ad.other_contributors.each do |co|
|
|
35
|
+
xml.other_contributors co
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
xml.lifecycle_state ad.lifecycle_state
|
|
39
|
+
xml.details do
|
|
40
|
+
ad.details.each do |lang, item|
|
|
41
|
+
xml.language do
|
|
42
|
+
xml.terminology_id do
|
|
43
|
+
xml.value item.language.terminology_id.value
|
|
44
|
+
end
|
|
45
|
+
xml.code_string lang
|
|
46
|
+
end
|
|
47
|
+
xml.purpose item.purpose
|
|
48
|
+
if item.keywords then
|
|
49
|
+
item.keywords.each do |word|
|
|
50
|
+
xml.keywords word
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
xml.use item.use if item.use
|
|
54
|
+
xml.misuse item.misuse if item.misuse
|
|
55
|
+
xml.copyright item.copyright if item.copyright
|
|
56
|
+
if ad.other_details
|
|
57
|
+
ad.other_details.each do |key,value|
|
|
58
|
+
xml.other_details(value, "id"=>key)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
return desc
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def definition
|
|
69
|
+
definition = ''
|
|
70
|
+
xml = Builder::XmlMarkup.new(:indent => 2, :target => definition)
|
|
71
|
+
xml.definition do
|
|
72
|
+
emit_c_object_body(xml, @archetype.definition)
|
|
73
|
+
end
|
|
74
|
+
return definition
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def ontology
|
|
78
|
+
ontology = ''
|
|
79
|
+
ao = @archetype.ontology
|
|
80
|
+
xml = Builder::XmlMarkup.new(:indent => 2, :target => ontology)
|
|
81
|
+
xml.ontology do
|
|
82
|
+
xml.specialisation_depth ao.specialisation_depth
|
|
83
|
+
(ao.languages_available || []).each { |lang| xml.languages_available lang }
|
|
84
|
+
(ao.terminologies_available || []).each { |t| xml.terminologies_available t }
|
|
85
|
+
xml.term_definitions do
|
|
86
|
+
ao.term_definitions.each do |lang, terms|
|
|
87
|
+
xml.language lang
|
|
88
|
+
xml.terms do
|
|
89
|
+
terms.each do |code, term|
|
|
90
|
+
xml.code code
|
|
91
|
+
xml.items do
|
|
92
|
+
term.items.each do |key, value|
|
|
93
|
+
xml.item do
|
|
94
|
+
xml.key key
|
|
95
|
+
xml.value value
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
emit_term_bindings(xml, ao.term_bindings)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def merge
|
|
108
|
+
archetype = "<?xml version='1.0' encoding='UTF-8'?>" + NL +
|
|
109
|
+
"<archetype xmlns=\"http://schemas.openehr.org/v1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + NL +
|
|
110
|
+
header + description + definition +
|
|
111
|
+
ontology + '</archetype>'
|
|
112
|
+
return archetype
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
include OpenEHR::AM::Archetype::ConstraintModel
|
|
116
|
+
Primitive = OpenEHR::AM::Archetype::ConstraintModel::Primitive
|
|
117
|
+
OpenEHRProfile = OpenEHR::AM::OpenEHRProfile
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
# Emits a C_OBJECT's own fields (rm_type_name/occurrence/node_id
|
|
122
|
+
# plus, unless any_allowed?, its attributes) directly into the
|
|
123
|
+
# current xml element - used both for the root <definition> and,
|
|
124
|
+
# via emit_child, for every nested C_COMPLEX_OBJECT.
|
|
125
|
+
def emit_c_object_body(xml, node)
|
|
126
|
+
xml.rm_type_name node.rm_type_name
|
|
127
|
+
xml.occurrence { emit_interval(xml, node.occurrences) }
|
|
128
|
+
xml.node_id node.node_id
|
|
129
|
+
return if node.any_allowed?
|
|
130
|
+
|
|
131
|
+
node.attributes.each { |a| emit_attribute(xml, a) }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def emit_interval(xml, interval)
|
|
135
|
+
xml.lower_included interval.lower_included? unless interval.lower_included?.nil?
|
|
136
|
+
xml.upper_included interval.upper_included? unless interval.upper_included?.nil?
|
|
137
|
+
xml.lower_unbounded interval.lower_unbounded?
|
|
138
|
+
xml.upper_unbounded interval.upper_unbounded?
|
|
139
|
+
xml.lower interval.lower
|
|
140
|
+
xml.upper interval.upper
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def emit_attribute(xml, attribute)
|
|
144
|
+
xml.attributes do
|
|
145
|
+
xml.rm_attribute_name attribute.rm_attribute_name
|
|
146
|
+
xml.existence { emit_interval(xml, attribute.existence) } if attribute.existence
|
|
147
|
+
emit_cardinality(xml, attribute.cardinality) if attribute.is_a?(CMultipleAttribute)
|
|
148
|
+
(attribute.children || []).each { |c| emit_child(xml, c) }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def emit_cardinality(xml, cardinality)
|
|
153
|
+
xml.cardinality do
|
|
154
|
+
next if cardinality.nil?
|
|
155
|
+
|
|
156
|
+
xml.is_ordered cardinality.is_ordered?
|
|
157
|
+
xml.is_unique cardinality.is_unique?
|
|
158
|
+
xml.interval { emit_interval(xml, cardinality.interval) } if cardinality.interval
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Dispatches an attribute's child node, tagging each <children>
|
|
163
|
+
# element with an xsi:type discriminator (the AOM node's class,
|
|
164
|
+
# in openEHR's own naming) since the children of one attribute
|
|
165
|
+
# can be a mix of concrete constraint node types.
|
|
166
|
+
def emit_child(xml, node)
|
|
167
|
+
case node
|
|
168
|
+
when ArchetypeSlot
|
|
169
|
+
xml.children('xsi:type' => 'ARCHETYPE_SLOT') { emit_archetype_slot_body(xml, node) }
|
|
170
|
+
when ArchetypeInternalRef
|
|
171
|
+
xml.children('xsi:type' => 'ARCHETYPE_INTERNAL_REF') { xml.target_path node.target_path }
|
|
172
|
+
when ConstraintRef
|
|
173
|
+
xml.children('xsi:type' => 'CONSTRAINT_REF') { xml.reference node.reference }
|
|
174
|
+
when CPrimitiveObject
|
|
175
|
+
xml.children('xsi:type' => 'C_PRIMITIVE_OBJECT') { emit_primitive_body(xml, node.item) }
|
|
176
|
+
when OpenEHRProfile::DataTypes::Quantity::CDvOrdinal
|
|
177
|
+
xml.children('xsi:type' => 'C_DV_ORDINAL') { emit_ordinal_body(xml, node) }
|
|
178
|
+
when OpenEHRProfile::DataTypes::Text::CCodePhrase
|
|
179
|
+
xml.children('xsi:type' => 'C_CODE_PHRASE') { emit_code_phrase_body(xml, node) }
|
|
180
|
+
when CComplexObject
|
|
181
|
+
xml.children('xsi:type' => 'C_COMPLEX_OBJECT') { emit_c_object_body(xml, node) }
|
|
182
|
+
else
|
|
183
|
+
raise ArgumentError, "XMLSerializer cannot emit a #{node.class} node"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def emit_archetype_slot_body(xml, node)
|
|
188
|
+
xml.rm_type_name node.rm_type_name
|
|
189
|
+
xml.occurrence { emit_interval(xml, node.occurrences) }
|
|
190
|
+
xml.node_id node.node_id if node.node_id
|
|
191
|
+
emit_assertions(xml, 'includes', node.includes)
|
|
192
|
+
emit_assertions(xml, 'excludes', node.excludes)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def emit_assertions(xml, tag, assertions)
|
|
196
|
+
return if assertions.nil?
|
|
197
|
+
|
|
198
|
+
xml.tag!(tag) { assertions.each { |a| xml.assertion a.string_expression } }
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def emit_primitive_body(xml, item)
|
|
202
|
+
xml.primitive_type item.type
|
|
203
|
+
if item.is_a?(Primitive::CBoolean)
|
|
204
|
+
xml.true_valid item.true_valid
|
|
205
|
+
xml.false_valid item.false_valid
|
|
206
|
+
elsif item.respond_to?(:pattern) && item.pattern
|
|
207
|
+
xml.pattern item.pattern
|
|
208
|
+
elsif item.list
|
|
209
|
+
item.list.each { |v| xml.item literal(v) }
|
|
210
|
+
elsif item.range
|
|
211
|
+
xml.range { emit_bound_interval(xml, item.range) }
|
|
212
|
+
end
|
|
213
|
+
xml.assumed_value literal(item.assumed_value) if item.has_assumed_value?
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def emit_bound_interval(xml, range)
|
|
217
|
+
xml.lower literal(range.lower) unless range.lower_unbounded?
|
|
218
|
+
xml.upper literal(range.upper) unless range.upper_unbounded?
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def literal(value)
|
|
222
|
+
value.respond_to?(:value) ? value.value.to_s : value.to_s
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def emit_ordinal_body(xml, node)
|
|
226
|
+
return if node.any_allowed?
|
|
227
|
+
|
|
228
|
+
node.list.each do |o|
|
|
229
|
+
xml.item do
|
|
230
|
+
xml.value o.value
|
|
231
|
+
xml.symbol o.symbol.code_string
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
xml.assumed_value literal(node.assumed_value) if node.has_assumed_value?
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def emit_code_phrase_body(xml, node)
|
|
238
|
+
return if node.any_allowed?
|
|
239
|
+
|
|
240
|
+
xml.terminology_id node.terminology_id.value
|
|
241
|
+
node.code_list.each { |c| xml.code c }
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def emit_term_bindings(xml, term_bindings)
|
|
245
|
+
return if term_bindings.nil?
|
|
246
|
+
|
|
247
|
+
term_bindings.each do |terminology, codes|
|
|
248
|
+
codes.each do |code, bindings|
|
|
249
|
+
code_phrase = Array(bindings).first
|
|
250
|
+
xml.term_bindings do
|
|
251
|
+
xml.terminology terminology
|
|
252
|
+
xml.code code
|
|
253
|
+
xml.value "#{code_phrase.terminology_id.value}::#{code_phrase.code_string}"
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
data/lib/openehr/serializer.rb
CHANGED
|
@@ -1,291 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
NL = "\r\n"
|
|
7
|
-
INDENT = ' '
|
|
8
|
-
|
|
9
|
-
class BaseSerializer
|
|
10
|
-
def initialize(archetype)
|
|
11
|
-
@archetype = archetype
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def serialize
|
|
15
|
-
return self.merge
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
def merge
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
class ADLSerializer < BaseSerializer
|
|
24
|
-
def header
|
|
25
|
-
hd = 'archetype'
|
|
26
|
-
unless @archetype.adl_version.nil?
|
|
27
|
-
hd << " (adl_version = #{@archetype.adl_version})"
|
|
28
|
-
end
|
|
29
|
-
hd << NL+INDENT + "#{@archetype.archetype_id.value}"+NL*2
|
|
30
|
-
hd << 'concept'+NL+ INDENT+"[#{@archetype.concept}]"+NL
|
|
31
|
-
hd << NL+'language'+NL+INDENT+'original_language = <['+
|
|
32
|
-
@archetype.original_language.terminology_id.value+'::'+
|
|
33
|
-
@archetype.original_language.code_string+']>'+NL
|
|
34
|
-
return hd
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def description
|
|
38
|
-
desc = ''
|
|
39
|
-
if @archetype.description
|
|
40
|
-
ad = @archetype.description
|
|
41
|
-
desc << 'description' + NL
|
|
42
|
-
desc << INDENT + 'original_author = <' + NL
|
|
43
|
-
ad.original_author.each do |k,v|
|
|
44
|
-
desc << INDENT+INDENT+'["'+k+'"] = <"'+v+'">'+NL
|
|
45
|
-
end
|
|
46
|
-
desc << INDENT+'>'+NL
|
|
47
|
-
desc << INDENT+'lifecycle_state = <"'+ad.lifecycle_state+'">'+NL
|
|
48
|
-
desc << INDENT+'details = <'+NL
|
|
49
|
-
ad.details.each do |lang,item|
|
|
50
|
-
desc << INDENT*2+'["'+lang+'"] = <'+NL
|
|
51
|
-
desc << INDENT*3+'language = <['+
|
|
52
|
-
item.language.terminology_id.value+'::'+
|
|
53
|
-
item.language.code_string+']>'+NL
|
|
54
|
-
desc << INDENT*3+'purpose = <"'+item.purpose+'">'+NL
|
|
55
|
-
if item.keywords then
|
|
56
|
-
desc << INDENT*3+'keywords = <'
|
|
57
|
-
item.keywords.each do |word|
|
|
58
|
-
desc << '"'+word+'",'
|
|
59
|
-
end
|
|
60
|
-
desc.chop! << '>'+NL
|
|
61
|
-
end
|
|
62
|
-
desc << INDENT*3+'use = <"'+item.use+'">'+NL if item.use
|
|
63
|
-
desc << INDENT*3+'misuse = <"'+item.misuse+'">'+NL if item.misuse
|
|
64
|
-
desc << INDENT*3+'copyright = <"'+item.copyright+'">'+NL if item.copyright
|
|
65
|
-
if item.original_resource_uri
|
|
66
|
-
desc << INDENT*3 + 'original_resource_uri = <'
|
|
67
|
-
item.original_resource_uri.each do |k,v|
|
|
68
|
-
desc << INDENT*4+'["'+k+'"] = <"'+v+'">'+NL
|
|
69
|
-
end
|
|
70
|
-
desc << INDENT*3+'>'+NL
|
|
71
|
-
end
|
|
72
|
-
if item.other_details
|
|
73
|
-
desc << INDENT*3 + 'other_details = <'
|
|
74
|
-
item.original_resource_uri.each do |k,v|
|
|
75
|
-
desc << INDENT*4+'["'+k+'"] = <"'+v+'">'+NL
|
|
76
|
-
end
|
|
77
|
-
desc << INDENT*3+'>'+NL
|
|
78
|
-
end
|
|
79
|
-
desc << INDENT*2+'>'+NL
|
|
80
|
-
end
|
|
81
|
-
desc << INDENT+'>'+NL
|
|
82
|
-
end
|
|
83
|
-
return desc
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def definition
|
|
87
|
-
ad = @archetype.definition
|
|
88
|
-
definition = 'definition'+NL
|
|
89
|
-
definition << INDENT+ad.rm_type_name+"[#{ad.node_id}] matches {"
|
|
90
|
-
if ad.any_allowed?
|
|
91
|
-
definition << '*}'+NL
|
|
92
|
-
else
|
|
93
|
-
definition << NL
|
|
94
|
-
if ad.attributes
|
|
95
|
-
attributes = ad.attributes
|
|
96
|
-
indents = 2
|
|
97
|
-
while attributes
|
|
98
|
-
definition << INDENT*indents+attributes.rm_type_name
|
|
99
|
-
definition << "[#{attributes.node_id}] "
|
|
100
|
-
definition << existence(attributes.existence)
|
|
101
|
-
definition << " matches {"
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def ontology
|
|
108
|
-
ao = @archetype.ontology
|
|
109
|
-
ontology = 'ontology'+NL
|
|
110
|
-
ontology << INDENT + 'term_definitions = <' + NL
|
|
111
|
-
ao.term_definitions.each do |lang, items|
|
|
112
|
-
ontology << INDENT*2 + "[\"#{lang}\"] = <" + NL
|
|
113
|
-
ontology << INDENT*3 + 'items = <' + NL
|
|
114
|
-
items.each do |item|
|
|
115
|
-
ontology << INDENT*4 + "[\"#{item.code}\"] = <" + NL
|
|
116
|
-
item.items.each do |name, desc|
|
|
117
|
-
ontology << INDENT*5 + "#{name} = <\"#{desc}\">" +NL
|
|
118
|
-
end
|
|
119
|
-
ontology << INDENT*4 + '>'+NL
|
|
120
|
-
end
|
|
121
|
-
ontology << INDENT*3 + '>' + NL
|
|
122
|
-
ontology << INDENT*2 + '>' + NL
|
|
123
|
-
end
|
|
124
|
-
ontology << INDENT + '>' + NL
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def merge
|
|
128
|
-
return header + NL + description + NL + definition + NL + ontology
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
private
|
|
132
|
-
def c_object
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def existence(existence)
|
|
136
|
-
"existence matches {#{existence.lower}..#{existence.upper}}"
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
class XMLSerializer < BaseSerializer
|
|
141
|
-
def header
|
|
142
|
-
header = ''
|
|
143
|
-
xml = Builder::XmlMarkup.new(:indent => 2, :target => header)
|
|
144
|
-
xml.archetype_id do
|
|
145
|
-
xml.value @archetype.archetype_id.value
|
|
146
|
-
end
|
|
147
|
-
xml.concept @archetype.concept
|
|
148
|
-
xml.original_language do
|
|
149
|
-
xml.terminology_id do
|
|
150
|
-
xml.value @archetype.original_language.terminology_id.value
|
|
151
|
-
end
|
|
152
|
-
xml.code_string @archetype.original_language.code_string
|
|
153
|
-
end
|
|
154
|
-
return header
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def description
|
|
158
|
-
desc = ''
|
|
159
|
-
xml = Builder::XmlMarkup.new(:indent => 2, :target => desc)
|
|
160
|
-
ad = @archetype.description
|
|
161
|
-
if ad
|
|
162
|
-
xml.description do
|
|
163
|
-
ad.original_author.each do |key,value|
|
|
164
|
-
xml.original_author(value,"id"=>key)
|
|
165
|
-
end
|
|
166
|
-
if ad.other_contributors
|
|
167
|
-
ad.other_contributors.each do |co|
|
|
168
|
-
xml.other_contributors co
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
xml.lifecycle_state ad.lifecycle_state
|
|
172
|
-
xml.details do
|
|
173
|
-
ad.details.each do |lang, item|
|
|
174
|
-
xml.language do
|
|
175
|
-
xml.terminology_id do
|
|
176
|
-
xml.value item.language.terminology_id.value
|
|
177
|
-
end
|
|
178
|
-
xml.code_string lang
|
|
179
|
-
end
|
|
180
|
-
xml.purpose item.purpose
|
|
181
|
-
if item.keywords then
|
|
182
|
-
item.keywords.each do |word|
|
|
183
|
-
xml.keywords word
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
xml.use item.use if item.use
|
|
187
|
-
xml.misuse item.misuse if item.misuse
|
|
188
|
-
xml.copyright item.copyright if item.copyright
|
|
189
|
-
if ad.other_details
|
|
190
|
-
ad.other_details.each do |key,value|
|
|
191
|
-
xml.other_details(value, "id"=>key)
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
return desc
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def definition
|
|
202
|
-
definition = ''
|
|
203
|
-
ad = @archetype.definition
|
|
204
|
-
xml = Builder::XmlMarkup.new(:indent => 2, :target => definition)
|
|
205
|
-
xml.definition do
|
|
206
|
-
xml.rm_type_name ad.rm_type_name
|
|
207
|
-
xml.occurrence do
|
|
208
|
-
oc = ad.occurrences
|
|
209
|
-
xml.lower_included oc.lower_included? unless oc.lower_included?.nil?
|
|
210
|
-
xml.upper_included oc.upper_included? unless oc.upper_included?.nil?
|
|
211
|
-
xml.lower_unbounded oc.lower_unbounded?
|
|
212
|
-
xml.upper_unbounded oc.upper_unbounded?
|
|
213
|
-
xml.lower oc.lower
|
|
214
|
-
xml.upper oc.lower
|
|
215
|
-
end
|
|
216
|
-
xml.node_id ad.node_id
|
|
217
|
-
end
|
|
218
|
-
return definition
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def ontology
|
|
222
|
-
ontology = ''
|
|
223
|
-
ao = @archetype.ontology
|
|
224
|
-
xml = Builder::XmlMarkup.new(:indent => 2, :target => ontology)
|
|
225
|
-
xml.ontology do
|
|
226
|
-
xml.specialisation_depth ao.specialisation_depth
|
|
227
|
-
xml.term_definitions do
|
|
228
|
-
ao.term_definitions.each do |lang, terms|
|
|
229
|
-
xml.language lang
|
|
230
|
-
xml.terms do
|
|
231
|
-
terms.each do |term|
|
|
232
|
-
xml.code term.code
|
|
233
|
-
xml.items do
|
|
234
|
-
term.items.each do |key, value|
|
|
235
|
-
xml.item do
|
|
236
|
-
xml.key key
|
|
237
|
-
xml.value value
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def merge
|
|
249
|
-
archetype = "<?xml version='1.0' encoding='UTF-8'?>" + NL +
|
|
250
|
-
"<archetype xmlns=\"http://schemas.openehr.org/v1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + NL +
|
|
251
|
-
header + description + definition +
|
|
252
|
-
ontology + '</archetype>'
|
|
253
|
-
return archetype
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
class OPTSerializer < BaseSerializer
|
|
258
|
-
def initialize(opt, format:)
|
|
259
|
-
@opt = OpenEHR::Parser::OPTParser.new(opt).parse
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def name
|
|
263
|
-
@opt.definition.archetype_id.concept_name
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def header
|
|
267
|
-
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
class Publisher
|
|
276
|
-
def initialize(serializer)
|
|
277
|
-
@serializer = serializer
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
def publish(writer)
|
|
281
|
-
writer.out(@serializer.serialize)
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
class Writer
|
|
286
|
-
def initialize(target)
|
|
287
|
-
@target = target
|
|
288
|
-
end
|
|
289
|
-
def out
|
|
290
|
-
end
|
|
291
|
-
end
|
|
1
|
+
require_relative 'serializer/base'
|
|
2
|
+
require_relative 'serializer/adl_serializer'
|
|
3
|
+
require_relative 'serializer/xml_serializer'
|
|
4
|
+
require_relative 'serializer/opt_serializer'
|
|
5
|
+
require_relative 'serializer/rm_json_serializer'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# OpenEHR::TerminologyService is the seam RM classes call through to
|
|
2
|
+
# validate codes against openEHR/external terminologies (e.g.
|
|
3
|
+
# COMPOSITION.language against ISO_639-1, COMPOSITION.category against
|
|
4
|
+
# the openEHR "composition category" group). This gem carries no
|
|
5
|
+
# terminology data of its own - that lives in the separate
|
|
6
|
+
# openehr-terminology gem - so the default provider is fully
|
|
7
|
+
# permissive: every code is accepted.
|
|
8
|
+
#
|
|
9
|
+
# To get real validation, plug in an adapter:
|
|
10
|
+
# OpenEHR::TerminologyService.provider = MyTerminologyAdapter.new
|
|
11
|
+
# where the adapter responds to:
|
|
12
|
+
# #valid_code?(terminology_id, code) -> Boolean
|
|
13
|
+
# #has_code_for_group?(group_id, code) -> Boolean
|
|
14
|
+
module OpenEHR
|
|
15
|
+
module TerminologyService
|
|
16
|
+
class NullProvider
|
|
17
|
+
def valid_code?(_terminology_id, _code)
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def has_code_for_group?(_group_id, _code)
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class << self
|
|
27
|
+
def provider
|
|
28
|
+
@provider ||= NullProvider.new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def provider=(provider)
|
|
32
|
+
@provider = provider || NullProvider.new
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def valid_code?(terminology_id, code)
|
|
36
|
+
provider.valid_code?(terminology_id, code)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def has_code_for_group?(group_id, code)
|
|
40
|
+
provider.has_code_for_group?(group_id, code)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/openehr/version.rb
CHANGED
data/lib/openehr.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require_relative 'openehr/version'
|
|
2
|
+
require_relative 'openehr/path'
|
|
3
|
+
require_relative 'openehr/terminology_service'
|
|
2
4
|
require_relative 'openehr/assumed_library_types'
|
|
3
5
|
|
|
4
6
|
#Reference model
|
|
@@ -9,6 +11,7 @@ require_relative 'openehr/am'
|
|
|
9
11
|
|
|
10
12
|
#Adl/xml parser/serializer
|
|
11
13
|
require_relative 'openehr/parser'
|
|
12
|
-
# require_relative 'openehr/parser/adl_parser'
|
|
13
|
-
# require_relative 'openehr/parser/xml_parser'
|
|
14
14
|
require_relative 'openehr/serializer'
|
|
15
|
+
|
|
16
|
+
#Archetype Query Language
|
|
17
|
+
require_relative 'openehr/aql'
|