Class: TemplateGenerator

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/ez7gen/service/template_generator.rb

Constant Summary collapse

DATAVALUES =

xml tags used in MWB schemas

'DataValues'
COMPONENT =
'Component'
SUBCOMPONENT =
'SubComponent'
COMP =

use xml tags as symbols for name of collections

COMPONENT.downcase.intern
SUB =
SUBCOMPONENT.downcase.intern
USAGES_REQ =

list of usages to be picked up, other ignored @@USAGES = [β€˜R’,β€˜RE’]

['R']
USAGES_OPT =
['RE']
@@HAT =

TODO: refactor in one place

'^'
@@SUB =

Component separator, aka hat

'&'

Constants included from Utils

Utils::BASE, Utils::BASE_INDICATOR, Utils::DATA_LOOKUP_MIS, Utils::PRIMARY

Instance Method Summary collapse

Methods included from Utils

#blank?, #get_name_without_base, #get_segment_name, #get_type_by_name, #has_html_encoded_ch?, #is_number?, #num_to_nil, #safe_len, #sample_index

Constructor Details

#initialize(tempalte_path, pp) ⇒ TemplateGenerator

initialise template generator with the path to template xml (MWB) and parcers



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/ez7gen/service/template_generator.rb', line 25

def initialize(tempalte_path, pp)

  # parse template  TODO: refactor if not needed on class level move to 'build_template_metadata'
  text = File.path(tempalte_path)
  @xml = Ox.parse(IO.read(text))

  #If there are multiple profile parsers, instantiate a generators for each
  @fieldGenerators = {}
  # helper parser for lookup in the other schema
  # when generating segments for custom (not base) ex VAZ2.4 the field generator will have to look in both schemas
  # to resolve types and coded tables value.
  # we will assign the other schema parser as a helper parser

  pp.each{|profileName, parser|
    helper_parser = pp.select{|key, value| key != profileName }
    helper_parser = (helper_parser.empty?) ? nil: helper_parser.values.first
    # a = TypeAwareFieldGenerator.new( parser, helper_parser)
    #@fieldGenerators[profileName] = a
    @fieldGenerators[profileName] = TypeAwareFieldGenerator.new( parser, helper_parser)
  }

end

Instance Method Details

#build_metadata(useExVal) ⇒ Object

using MWB profiles build collection of message metadata, to use for building a message



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/ez7gen/service/template_generator.rb', line 131

def (useExVal)
  meta = {}
  segments = []

  # list of segments
  # In the event of Subgroups of Segments defined in the template, find them and allow
  # groups only once for simplicity.
  if( @xml.HL7v2xConformanceProfile.HL7v2xStaticDef.locate('SegGroup')) then
    nodes = @xml.HL7v2xConformanceProfile.HL7v2xStaticDef.nodes

    nodes.each{|node|
      if (node.value == "Segment") then
        segments << node
      elsif (node.value == "SegGroup")then
        segments << node.locate('Segment')
      end
    }
    segments.flatten!
  else
    segments = @xml.HL7v2xConformanceProfile.HL7v2xStaticDef.locate('Segment')
    end

  segments.each{|seg|

    fields = []
    seg.locate('Field').each_with_index { |f,idx |
      # if (@@USAGES.include?(f.Usage))
      if use?(f.Usage)
        f.attributes.merge!(:Pos => idx)
        fields << (f,useExVal)
      end
    }

    meta[seg.attributes[:Name]] = fields
  }

  return meta
end

#build_partial_field_data(item) ⇒ Object

convert



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/ez7gen/service/template_generator.rb', line 113

def build_partial_field_data(item)
  # use the Example Value 'ExValue' defined in the xml file instead
  if(item[:ExValue]) then return item[:ExValue] end

  # convert attributes from MWB into Ensemble and use the
  attrs = {}
  # strip leading zeros from table name, MWB format.
  if (item[:Table]) then attrs[:codetable]= item[:Table].sub(/^0+/, '') end
  if (item[:Length]) then attrs[:max_length]= item[:Length] end
  if (item[:Name]) then attrs[:description] = item[:Name] end
  if (item[:Datatype]) then attrs[:datatype] = item[:Datatype] end

  # return genereated field
  # use primary field generator, as templates only work for custom schema.
  @fieldGenerators[PRIMARY].method(attrs[:datatype]).call(attrs, true)
end

#generate(message, useExVal) ⇒ Object

build hl7 message using template as guideline def generate(message, template, parsers, isGroup=false)



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/ez7gen/service/template_generator.rb', line 50

def generate(message, useExVal)
  # read MWB xml file into collection of metadata for each segment
   = (useExVal)

  # segment names
  segments = .keys

  # add each segment to message using template metadata
  segments.each{|segName|
    meta = [segName]
    processed = process_partials(meta)
    message << generate_segment(segName, processed)
  }

  return message
end

#generate_segment(segmentName, attributes, idx = nil) ⇒ Object

generate a segment using Ensemble schema



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/ez7gen/service/template_generator.rb', line 68

def generate_segment(segmentName, attributes, idx=nil)
  # elements = generate_segment_elements(segmentName, attributes)
  attributes.unshift(get_name_without_base(segmentName))
  # elements = generate_segment_elements(segmentName, attributes)
  # overrite ids for sequential repeating segments
  # elements[@@SET_ID_PIECE] = handle_set_id(segmentName, attributes, idx) || elements[@@SET_ID_PIECE]

  #generate segment using elements
  if(segmentName == 'MSH')
    attributes.slice!(1)
    # one = two.first + two.last
    # attributes.insert(1,one)
  end
  return HL7::Message::Segment::Default.new(attributes)
end

#get_metadata(partial, useExVal) ⇒ Object

parse template xml file into collection



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/ez7gen/service/template_generator.rb', line 171

def (partial, useExVal)

  element = partial.locate(COMPONENT)

  # first look for DataValues example if it's there use it and stop looking any farther.
  if(useExVal && (element.empty?) && !partial.locate(DATAVALUES).empty?)
      exVal = partial.locate(DATAVALUES).first.attributes
      partial.attributes.merge!(exVal)
      return partial.attributes
  end

  # continue looking for subcomponents
  element = (element.empty?) ? partial.locate(SUBCOMPONENT) : element
  if(!element.empty?)
      sub = []

      element.each_with_index { |el, idx|

        if (use?(el[:Usage])) # required or optional
          el.attributes.merge!(:Pos => idx)
          sub << (el, useExVal)
        end

      }

      if(!sub.empty?)
        subElementName = (element.first.value.downcase).intern # subcomponent or component
        partial.attributes[subElementName] = sub
      end

  end

  return partial.attributes

end

#process_partials(item) ⇒ Object

working with template hash brake field metadata to components and then to subcomponents



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/ez7gen/service/template_generator.rb', line 85

def process_partials(item)
  partials = []

  # process each sub type
  if(item.kind_of? Array)

    item.each{|subType| # at this level we have components or subcomponents
      coll = subType[SUB] || subType # if subcomponents found process again
      unit = process_partials(coll)
      flag = (subType[SUB]) ? @@SUB : @@HAT
      partials[subType[:Pos].to_i] = unit.join(flag)
    }

  else
    # check for components first and then subcomponents
    coll = item[COMP] || item[SUB]
    if(coll)
      partials << process_partials(coll)
    else
      partials << build_partial_field_data(item)
    end
  end

  return partials

end

#use?(usage) ⇒ Boolean

Returns:

  • (Boolean)


207
208
209
210
211
# File 'lib/ez7gen/service/template_generator.rb', line 207

def use?(usage)
  # check for required field/compnent/subcomponent: R
  # if not toss a coin for optional (required or empty): RE (required or empty)
  return (USAGES_REQ.include?(usage)) ? true : (USAGES_OPT.include?(usage) && [true,false].sample)
end