Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Parse XML Annotation Files and retrieve time asleep and number of obstructive apnea events.
# frozen_string_literal: true
# gem install xml-simple colorize --no-document
# ruby annotation_testing.rb
require 'rubygems'
require 'colorize'
require 'json'
require 'xmlsimple'
# Take the XML files in this folder `/annotation-testing` and answer two
# questions:
# 1) How many epochs/minutes was the subject asleep?
# 2) How many obstructive apnea events were marked on the recording?
# Asleep is defined as SleepStage = 1,2,3,4,5
def extract(hash, key, convert: nil)
value = hash[key] ? hash[key][0] : nil
convert && value ? value.send(convert) : value
Dir.glob('**/*.xml', File::FNM_CASEFOLD).each do |xml_path|
xml = XmlSimple.xml_in(xml_path)
epoch_length = xml['EpochLength'][0].to_i
sleep_stages = xml['SleepStages'][0]['SleepStage']
# awake_stages = { |stage| %w(0).include?(stage) }
asleep_stages = { |stage| %w(1 2 3 4 5).include?(stage) }
scored_events = xml['ScoredEvents'][0]['ScoredEvent'].collect do |hash|
name: extract(hash, 'Name'),
lowest_spo2: extract(hash, 'LowestSpO2', convert: :to_f),
desaturation: extract(hash, 'Desaturation', convert: :to_f),
start: extract(hash, 'Start', convert: :to_f),
duration: extract(hash, 'Duration', convert: :to_f),
input: extract(hash, 'Input')
obstructive_apnea_events = do |event|
event[:name] == 'Obstructive Apnea'
message = \
"The subject was asleep for #{asleep_stages.count} of total "\
"#{sleep_stages.count} sleep stages.\nThis comes to "\
"#{(asleep_stages.count * epoch_length / 60.0).to_s.colorize(:green)} "\
"minutes of #{sleep_stages.count * epoch_length / 60.0} minutes total.\n"\
"#{obstructive_apnea_events.count.to_s.colorize(:green)} obstructive apnea"\
" were scored.\n\n"
puts message
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.