-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse-apple-health.go
85 lines (72 loc) · 1.65 KB
/
parse-apple-health.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package main
import (
"encoding/csv"
"encoding/xml"
"fmt"
"os"
)
const (
BodyWeightKey = "HKQuantityTypeIdentifierBodyMass"
)
type ParseAppleHealthXML struct {
Out string `help:"Output file" name:"out" type:"path" short:"o"`
XMLFile string `help:"Apple Health XML file to parse" name:"xml-file" type:"existingfile" short:"i"`
}
type HealthData struct {
RecordType string `xml:"type,attr"`
StartDate string `xml:"startDate,attr"`
EndDate string `xml:"endDate,attr"`
Value float64 `xml:"value,attr"`
}
func (a *ParseAppleHealthXML) Run() error {
// Open XML file
file, err := os.Open(a.XMLFile)
if err != nil {
return err
}
defer func(file *os.File) {
_ = file.Close()
}(file)
// Create output file
outFile, err := os.Create(a.Out)
if err != nil {
return err
}
defer func(outFile *os.File) {
_ = outFile.Close()
}(outFile)
// Create CSV writer
writer := csv.NewWriter(outFile)
defer writer.Flush()
if err := writeContents(file, writer); err != nil {
_ = os.Remove(a.Out)
return err
}
return nil
}
func writeContents(inputFile *os.File, outWriter *csv.Writer) error {
err := outWriter.Write([]string{"Date", "Weight"})
if err != nil {
return err
}
decoder := xml.NewDecoder(inputFile)
for {
token, err := decoder.Token()
if err != nil {
break
}
elem, ok := token.(xml.StartElement)
if ok && elem.Name.Local == "Record" {
var hd HealthData
err := decoder.DecodeElement(&hd, &elem)
if err != nil {
return err
}
if hd.RecordType == BodyWeightKey {
// Write weight data to CSV
_ = outWriter.Write([]string{hd.StartDate, fmt.Sprintf("%f", hd.Value)})
}
}
}
return nil
}