OK. I finally upgraded to iOS 16. I saved a copy of my iOS 15 Health Data for comparison.
I usually try to give Apple the benefit of the doubt. But this case, Apple completely screwed this up. Not even close.
First of all, Apple is still using DTD files. That's surprising. Plus, it is embedded rather than referencing a URL. That's unusual. Most importantly, Apple scrambled the syntax so it won't ever work. Note to Apple, use a schema instead and do it correctly. No other way to say it.
Edit: in addition to the above, Apple flat-out did the DTD incorrectly. I fixed the scrambled syntax and was able to get "xmllint" happy, but it still failed validation. So I went ahead and fixed the DTD too.
Next, Apple scrambled the output of some elements, repeating the "startDate" attribute twice. The standard rule of thumb is to use a proper XML-processing library to generate XML for output. But those old XML libraries are cryptic and difficult to use. And sometimes, vendors who provide XML-processing libraries release buggy ones (that dig's for you, too, Apple 😄 ). So often, developers take shortcuts and just spit out text that they hope will be valid XML. Full disclosure, I do this myself. But if you roll your own, you've got to do it correctly. Apple failed at that.
There are two distinct fixes you will have to apply. I will write this out as a longer sequence of steps just to make things crystal clear.
1) Export your health data. I saved mine to my iCloud Drive. You'll definitely need a Mac to fix this.
2) Go into your iCloud Drive, or wherever you saved the file and expand the "export.zip" file. It will be expanded into a folder named "apple_health_export". For ease of description, I copied my file to "/tmp" and exported it there.
3) In the Terminal, navigate to that folder using "cd /tmp/apple_health_export". (Not including quotes)
4) Create a new filed called "patch.txt" with the following content:
--- export.xml 2022-09-18 15:17:09.000000000 -0400
+++ export-fixed.xml 2022-09-18 16:37:08.000000000 -0400
@@ -15,6 +15,7 @@
HKCharacteristicTypeIdentifierBiologicalSex CDATA #REQUIRED
HKCharacteristicTypeIdentifierBloodType CDATA #REQUIRED
HKCharacteristicTypeIdentifierFitzpatrickSkinType CDATA #REQUIRED
+ HKCharacteristicTypeIdentifierCardioFitnessMedicationsUse CDATA #IMPLIED
>
<!ELEMENT Record ((MetadataEntry|HeartRateVariabilityMetadataList)*)>
<!ATTLIST Record
@@ -39,7 +40,7 @@
startDate CDATA #REQUIRED
endDate CDATA #REQUIRED
>
-<!ELEMENT Workout ((MetadataEntry|WorkoutEvent|WorkoutRoute)*)>
+<!ELEMENT Workout ((MetadataEntry|WorkoutEvent|WorkoutRoute|WorkoutStatistics)*)>
<!ATTLIST Workout
workoutActivityType CDATA #REQUIRED
duration CDATA #IMPLIED
@@ -63,7 +64,7 @@
duration CDATA #IMPLIED
durationUnit CDATA #IMPLIED
>
-<!ELEMENT WorkoutEvent EMPTY>
+<!ELEMENT WorkoutEvent (MetadataEntry?)>
<!ATTLIST WorkoutEvent
type CDATA #REQUIRED
date CDATA #REQUIRED
@@ -79,6 +80,7 @@
minimum CDATA #IMPLIED
maximum CDATA #IMPLIED
sum CDATA #IMPLIED
+ unit CDATA #IMPLIED
>
<!ELEMENT WorkoutRoute ((MetadataEntry|FileReference)*)>
<!ATTLIST WorkoutRoute
@@ -153,6 +155,7 @@
dateIssued CDATA #REQUIRED
expirationDate CDATA #REQUIRED
brand CDATA #IMPLIED
+>
<!ELEMENT RightEye EMPTY>
<!ATTLIST RightEye
sphere CDATA #IMPLIED
@@ -203,13 +206,6 @@
diameter CDATA #IMPLIED
diameterUnit CDATA #IMPLIED
>
- device CDATA #IMPLIED
-<!ELEMENT MetadataEntry EMPTY>
-<!ATTLIST MetadataEntry
- key CDATA #IMPLIED
- value CDATA #IMPLIED
->
->
]>
<HealthData>
<ExportDate/>
Ignore the colours. That is just something the forum software adds to a code block.
5) Run the following command to patch your XML export file: "patch < patch.txt". (Again, omit the quotes.) The output should look like this:
patching file export.xml
Hunk #6 succeeded at 206 with fuzz 2.
Don't worry about that hunk #6 warning. I had to manually hack the patch file since it originally included two lines of content, which would be different. Luckily, patch gracefully handles it.
All this command does is replace the DTD data with something correct.