AppleHealthCareデータをNokogiriでパースする

hatappi.hateblo.jp

最近AppleWatchで収集した自分のヘルスケアデータをRailsで処理しはじめた
ヘルスケアデータはexport_cda.xml書き出す.xmlがある

今回はexport_cda.xmlから心拍数の一覧を取り出すのをゴールにする

Rubyでどう処理するか

個人的にもよく使っているnokogiriを使用することにした

github.com

普段は Nokogiri::HTMLでHTMLをパースすることが多いがxmlの時はNokogiri::XMLを使うことが出来る

Parsing

まずはexport_cda.xmlを読み込む

>  doc = File.open('export_cda.xml') { |f| Nokogiri::XML(f) }

次にパスを指定して心拍数一覧を取得

> doc.xpath("/ClinicalDocument/entry/organizer/component/observation/text/type[text()='HKQuantityTypeIdentifierHeartRate']/../value").map(&:text).join(',')
# => ""

がしかしとれない
xmlファイルを開いて見てみる

<ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 ../../../CDA%20R2/cda-schemas-and-samples/infrastructure/cda/CDA.xsd" xmlns="urn:hl7-org:v3" xmlns:cda="urn:hl7-org:v3" xmlns:sdtc="urn:l7-org:sdtc" xmlns:fhir="http://hl7.org/fhir/v3">

何やら色々かかれている
xmlは複数のマークアップ言語を扱うことが出来るが、それぞれの仕様が衝突しないように名前空間を設定することが出来る
その時使われるのがxmlnsで今回はNokogiri側でその名前空間が考慮されていなかった

さきほどのxpathを下記のように名前空間を指定することで取得ができるようになる

> doc.xpath("/ns:ClinicalDocument/ns:entry/ns:organizer/ns:component/ns:observation/ns:text/ns:type[text()='HKQuantityTypeIdentifierHeartRate']/../ns:value", {ns: "urn:hl7-org:v3"}).map(&:text).join(',')
# => "41,81,81,88,83,81,89,74,77,74,83,81,76,74,78,72,70,79,74,69,74,74,74,74,74,69,69,75,80,87,74,74,71,84,86,81,74"

とれた!!
ただ毎回名前空間を指定するのは面倒な時はnokogiri側に名前空間を取り除くメソッドがはえており下記のようにしようすることが出来る

> doc.remove_namespaces! # xmlから名前空間を取り除く
> doc.xpath("/ClinicalDocument/entry/organizer/component/observation/text/type[text()='HKQuantityTypeIdentifierHeartRate']/../value").map(&:text).join(',')
# => "41,81,81,88,83,81,89,74,77,74,83,81,76,74,78,72,70,79,74,69,74,74,74,74,74,69,69,75,80,87,74,74,71,84,86,81,74"