Class: ImzML::Sax

Inherits:
Ox::Sax
  • Object
show all
Defined in:
lib/imzml/parser.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSax

Returns a new instance of Sax.



38
39
40
41
42
43
44
45
46
# File 'lib/imzml/parser.rb', line 38

def initialize()
  @metadata = Metadata.new
  @stack = Array.new
  @elements = Array.new

  # temporary values useful just for data parsing
  @reference_groups = Hash.new
  @obo = Hash.new
end

Instance Attribute Details

#binary_filepathObject

Returns the value of attribute binary_filepath.



32
33
34
# File 'lib/imzml/parser.rb', line 32

def binary_filepath
  @binary_filepath
end

#intensity_binary_data_typeObject

Returns the value of attribute intensity_binary_data_type.



36
37
38
# File 'lib/imzml/parser.rb', line 36

def intensity_binary_data_type
  @intensity_binary_data_type
end

#metadataObject (readonly)

Returns the value of attribute metadata.



31
32
33
# File 'lib/imzml/parser.rb', line 31

def 
  @metadata
end

#mz_binary_data_typeObject

Both can have one of the symbols [:int8, :int16, :int32, :int64, :float32, :float64]



35
36
37
# File 'lib/imzml/parser.rb', line 35

def mz_binary_data_type
  @mz_binary_data_type
end

Instance Method Details

#attr(name, str) ⇒ Object



63
64
65
66
67
# File 'lib/imzml/parser.rb', line 63

def attr(name, str)
  element = @elements.last
  return if element.nil? # skip attributes without correct elements (like <?xml ...)
  element[name] = str
end

#end_element(name) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
169
170
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/imzml/parser.rb', line 69

def end_element(name)
  @stack.pop
  element = @elements.pop
  # p @stack

  # open OBO file for each from CV list for further validation
  if name == :cvList
    @cv_list.each do |cv|
      filename = case cv[:id]
      when "MS"
        "psi-ms.obo"
      when "UO"
        "unit.obo"
      when "IMS"
        "imagingMS.obo"
      end
      filepath = File.join(File.dirname(__FILE__), "..", "..", "data", filename)
      @obo[cv[:id].to_s] = Obo::Parser.new(filepath)
    end
  end

  # save file content
  if name == :cvParam && @stack.last == :fileContent

    cv = @obo[element[:cvRef]]
    stanza = cv.stanza(element[:accession])
    parent_id = stanza.parent_id

    # init basic structures
    @metadata.file_description ||= FileDescription.new
    file_content = (@metadata.file_description.file_content ||= FileContent.new)

    case element[:cvRef]
    when "MS"
      # save data file content
      if parent_id == FileContent::DATA_FILE_CONTENT
        file_content.data_file_contents ||= Hash.new
        (file_content.data_file_contents[parent_id] ||= Array.new) << element
      end

      # save spectrum representation
      if parent_id == FileContent::SPECTRUM_REPRESENTATION
        file_content.spectrum_representation = element
      end

    when "IMS"
      # save binary type (cannot look by parent because the OBO file is different and
      # the parser doesn't hadle it well, need to first improve the OBO parser)
      if stanza.id == FileContent::CONTINUOUS
        file_content.binary_type = :continuous
      elsif stanza.id == FileContent::PROCESSED
        file_content.binary_type = :processed
      end

      # save checksum type
      if stanza.id == FileContent::MD5
        file_content.checksum = element[:value]
      elsif stanza.id == FileContent::SHA1
        file_content.checksum = element[:value]
      end

      # save identifier
      if stanza.id == FileContent::UNIVERSALLY_UNIQUE_IDENTIFIER
        file_content.uuid = element[:value]
      end
    end

  end

  # save reference group for further usage
  if name == :cvParam && @stack.last == :referenceableParamGroup
    (@reference_groups[@elements.last[:id].to_sym] ||= Array.new) << element
  end

  # save sample list
  if name == :cvParam && @stack.last == :sample
    samples = (@metadata.samples ||= Hash.new)
    samples[@elements.last[:id].to_sym] = element
  end

  # save software list (raw, without detailed parsing)
  if name == :software && @stack.last == :softwareList
    (@metadata.software ||= Array.new) << element
  end

  # save scan settings
  if name == :cvParam && @stack.last == :scanSettings
    scan_settings = (@metadata.scan_settings ||= Hash.new)
    setting = (scan_settings[@elements.last[:id].to_sym] ||= ScanSettings.new)

    cv = @obo[element[:cvRef]]
    stanza = cv.stanza(element[:accession])
    parent_id = stanza.parent_id

    case element[:cvRef]
    when "IMS"

      # detect correct line scan direction
      setting.line_scan_direction = case stanza.id
      when ScanSettings::LINE_SCAN_BOTTOM_UP
        :bottom_up
      when ScanSettings::LINE_SCAN_LEFT_RIGHT
        :left_right
      when ScanSettings::LINE_SCAN_RIGHT_LEFT
        :right_left
      when ScanSettings::LINE_SCAN_TOP_DOWN
        :top_down
      else
        setting.line_scan_direction
      end

      # detect scan direction
      setting.scan_direction = case stanza.id
      when ScanSettings::BOTTOM_UP
        :bottom_up
      when ScanSettings::LEFT_RIGHT
        :left_right
      when ScanSettings::RIGHT_LEFT
        :right_left
      when ScanSettings::TOP_DOWN
        :top_down
      else
        setting.scan_direction
      end

      # detect scan pattern
      setting.scan_pattern = case stanza.id
      when ScanSettings::MEANDERING
        :meandering
      when ScanSettings::ONE_WAY
        :one_way
      when ScanSettings::RANDOM_ACCESS
        :random_access
      when ScanSettings::FLY_BACK
        :fly_back
      else
        setting.scan_pattern
      end

      # detect scan type
      setting.scan_type = case stanza.id
      when ScanSettings::HORIZONTAL_LINE_SCAN
        :horizontal
      when ScanSettings::VERTICAL_LINE_SCAN
        :vertical
      else
        setting.scan_type
      end

      # detect image properties
      image = (setting.image ||= ImzML::Image.new)

      case stanza.id
      when ScanSettings::MAX_DIMENSION_X
        point = (image.max_dimension ||= ImzML::Point.new)
        point.x = element[:value].to_i
      when ScanSettings::MAX_DIMENSION_Y
        point = (image.max_dimension ||= ImzML::Point.new)
        point.y = element[:value].to_i
      when ScanSettings::MAX_COUNT_OF_PIXEL_X
        point = (image.max_pixel_count ||= ImzML::Point.new)
        point.x = element[:value].to_i
      when ScanSettings::MAX_COUNT_OF_PIXEL_Y
        point = (image.max_pixel_count ||= ImzML::Point.new)
        point.y = element[:value].to_i
      when ScanSettings::PIXEL_SIZE_X
        point = (image.pixel_size ||= ImzML::Point.new)
        point.x = element[:value].to_i
      when ScanSettings::PIXEL_SIZE_Y
        point = (image.pixel_size ||= ImzML::Point.new)
        point.y = element[:value].to_i
      end
    end
    
  end

  # parse processing methods
  if name == :cvParam && @stack.last == :processingMethod
    data_processing = (@metadata.data_processing ||= Hash.new)
    processing = (data_processing[@elements[-2][:id].to_sym] ||= DataProcessing.new)
    processing.processing_method = @elements.last
    (processing.processing_method[:actions] ||= Array.new) << element
  end

  # save spectrum position info
  if name == :cvParam && @stack.last == :scan
    spectrums = (@metadata.spectrums ||= Hash.new)
    spectrum = (spectrums[@elements[-3][:id].to_sym] ||= Spectrum.new)
    point = (spectrum.position ||= ImzML::Point.new)
    
    point.x = element[:value].to_i if element[:accession] == Spectrum::POSITION_X
    point.y = element[:value].to_i if element[:accession] == Spectrum::POSITION_Y
  end
  
  # save spectrum binary data info
  if name == :referenceableParamGroupRef && @stack.last == :binaryDataArray
    group = @reference_groups[element[:ref].to_sym]
    
    spectrum = @metadata.spectrums[@elements[-3][:id].to_sym]
    mz_binary = (spectrum.mz_binary ||= ImzML::Spectrum::BinaryData.new)
    intensity_binary = (spectrum.intensity_binary ||= ImzML::Spectrum::BinaryData.new)
    
    # detect type of the binary data info based on referenced group content
    group.each do |param|
      # p param
      @binary_type = case param[:accession]
      when ImzML::Spectrum::BinaryData::MZ_ARRAY
        :mz_binary
      when ImzML::Spectrum::BinaryData::INTENSITY_ARRAY
        :intensity_binary
      end
      
      break if !@binary_type.nil?
    end
    
    # detect binary data type
    number_type = nil
    group.each do |param|
      number_type = case param[:accession]
      when Spectrum::BinaryData::BINARY_TYPE_8BIT_INTEGER
        :int8
      when Spectrum::BinaryData::BINARY_TYPE_16BIT_INTEGER
        :int16
      when Spectrum::BinaryData::BINARY_TYPE_32BIT_INTEGER
        :int32
      when Spectrum::BinaryData::BINARY_TYPE_64BIT_INTEGER
        :int64
      when Spectrum::BinaryData::BINARY_TYPE_32BIT_FLOAT
        :float32
      when Spectrum::BinaryData::BINARY_TYPE_64BIT_FLOAT
        :float64
      end
      
      break if !number_type.nil?
    end
    self.send("#{@binary_type.to_s}_data_type=", number_type) if !number_type.nil?
  end
  
  # save info about binary
  if name == :cvParam && @stack.last == :binaryDataArray 
    spectrum = @metadata.spectrums[@elements[-3][:id].to_sym]
    
    # convert chosen type to mz_binary/intensity_binary property selector
    binary_data = spectrum.send(@binary_type.to_s)
    binary_data.filepath = binary_filepath
    binary_data.type = self.send("#{@binary_type}_data_type")
    case element[:accession]
    when ImzML::Spectrum::BinaryData::EXTERNAL_ARRAY_LENGTH
      binary_data.length = element[:value].to_i
    when ImzML::Spectrum::BinaryData::EXTERNAL_OFFSET
      binary_data.offset = element[:value].to_i
    when ImzML::Spectrum::BinaryData::EXTERNAL_ENCODED_LENGHT
      binary_data.encoded_length = element[:value].to_i
    end 
  
  end
  
  # p @metadata.spectrums if name == :binaryDataArray

  # p "#{name} ended #{element}"

end

#start_element(name) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/imzml/parser.rb', line 48

def start_element(name)
  # p "#{@stack.last} #{@elements.last}"
  @stack.push(name)
  @elements.push(Hash.new)
  # p "#{name} started"
  # p @stack

  case name
  when :cvList
    @cv_list = []
  when :cv
    @cv_list << @elements.last
  end
end