Repository for the HealthTool which enables Apple users to analyse their health data from the Apple health app and prepares the data for contributing it for future studies on wearable data.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

286 lines
7.0 KiB

package application.parsing;
import java.text.ParseException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import application.enums.BiologicalSex;
import application.enums.BloodType;
import application.enums.EntryType;
import application.enums.SkinType;
import application.helpers.Utils;
import application.res.Text;
/**
* This class is in charge of reading in the data of the file and getting an overview of the data.
* @author Bianca
*
*/
public class ReadHandler extends DefaultHandler
{
/** The date the health data was exported**/
private String exportDate;
/** the biological sex given in the health data **/
private BiologicalSex bSex;
/** the blood type given in the health data **/
private BloodType bloodType;
/** the skin type given in the health data **/
private SkinType skinType;
/** the region code given in the health data **/
private String regionCode;
/** the date of birth as a string given in the health data**/
private String dateOfBirthString;
/** the date of birth saved in a calendar**/
private Calendar dateOfBirth;
/** contains as a key the name of tags (e.g EntryTypes) and as value the number of occurrences**/
private HashMap<String, Integer> names=new HashMap<>();
/** contains as a key the name of the sub workout and as value the number of occurrences **/
private HashMap<String, Integer> subWorkouts=new HashMap<>();
/** contains as a key the name of the sub records and as value the number of occurrences **/
private HashMap<String, Integer> subRecords=new HashMap<>();
/** keeps track of the tag layer. With every new element we increase the layer by one**/
private int overallLayer=0;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
//increase layer
if(overallLayer>0)
{
overallLayer++;
}
if (qName.equalsIgnoreCase(Text.TAG_NAME_HEALTH_DATA))
{ //outermost tag (overallLayer==0)
overallLayer++;
regionCode=attributes.getValue(Text.TAG_ATTR_REGION_CODE);
}
else if (qName.equalsIgnoreCase(EntryType.EXPORT_DATE.getValue()))
{
exportDate=attributes.getValue(Text.TAG_ATTR_EXPORT_DATE);
}
else if (qName.equalsIgnoreCase(Text.TAG_NAME_ME_INFO))
{
bSex = BiologicalSex.getValue(attributes.getValue(Text.TAG_ATTR_BIOLOGICAL_SEX));
dateOfBirthString = attributes.getValue(Text.TAG_ATTR_DATE_OF_BIRTH);
bloodType = BloodType.getValue(attributes.getValue(Text.TAG_ATTR_BLOOD_TYPE));
skinType = SkinType.getValue(attributes.getValue(Text.TAG_ATTR_SKIN_TYPE));
if(dateOfBirthString!=null&&!dateOfBirthString.equals(""))
{
try
{
dateOfBirth=new GregorianCalendar();
dateOfBirth.setTime(Utils.formatDateOfBirth.parse(dateOfBirthString));
} catch (ParseException e)
{
dateOfBirth=null;
//do nth if parsing error
}
}
}
else if (qName.equalsIgnoreCase(EntryType.RECORD.getValue()))
{
String subRecord=attributes.getValue(Text.TAG_ATTR_RECORD_TYPE);
Integer j = subRecords.get(subRecord);
if (j == null)
{
j = 0;
}
subRecords.put(subRecord, ++j);
}
else if (qName.equalsIgnoreCase(EntryType.WORKOUT.getValue()))
{
String subWorkout=attributes.getValue(Text.TAG_ATTR_WORKOUT_TYPE);
Integer j = subWorkouts.get(subWorkout);
if (j == null)
{
j = 0;
}
subWorkouts.put(subWorkout, ++j);
}
if(overallLayer==2) //layer 2 means direct descendants of the document root (HealthData-tag)
{
Integer v=names.get(qName);
if (v==null)
{
v=0;
}
names.put(qName, ++v);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
//decrease layer
if(overallLayer>0)
{
overallLayer--;
}
}
/**
* Returns the selected value from ME or ExportDate.
*
* @param type Value to find the info for.
* @return Found value if it was a valid entry of ME or the export Date,
* {@code null} otherwise
*/
public String getMeInfo(EntryType type)
{
if (type.equals(EntryType.BIOLOGICAL_SEX))
{
return bSex.getReadableValue();
} else if (type.equals(EntryType.DATE_OF_BIRTH))
{
return getDateOfBirth();
}
if (type.equals(EntryType.BLOOD_TYPE))
{
return bloodType.getReadableValue();
}
if (type.equals(EntryType.SKIN_TYPE))
{
return skinType.getReadableValue();
}
return null;
}
/**
* Returns the day the health data was exported
* @return the described value.
*/
public String getExportDate()
{
return exportDate;
}
/**
* Returns the region code given in the file.
* @return the described value.
*/
public String getRegionCode()
{
return regionCode;
}
/**
* Finds out how many Entries of the given EntryTypes can be found in the
* document
*
* @param type EntryType to find the count to
* @return 0 if there are none, otherwise the correct number of entries
*/
public int getTypeNumber(EntryType type)
{
if (names.get(type.getValue()) == null)
{
return 0;
}
return names.get(type.getValue());
}
/**
* Returns the year of birth if the data was given in the file. Otherwise returns -1.
* @return the described value.
*/
public int getDateOfBirthYear()
{
if(dateOfBirth!=null)
{
return dateOfBirth.get(Calendar.YEAR);
}
return -1;
}
/**
* Returns the month of birth if the data was given in the file. Otherwise returns -1.
* @return the described value.
*/
public int getDateOfBirthMonth()
{
if(dateOfBirth!=null)
{
return dateOfBirth.get(Calendar.MONTH)+1;
}
return -1;
}
/**
* Returns the day of birth if the data was given in the file. Otherwise returns -1.
* @return the described value.
*/
public int getDateOfBirthDay()
{
if(dateOfBirth!=null)
{
return dateOfBirth.get(Calendar.DAY_OF_MONTH);
}
return -1;
}
/**
* Returns the SubWorkouts with their respective occurrences
* @return The described value
*/
public HashMap<String, Integer> getSubWorkouts()
{
return subWorkouts;
}
/**
* Returns the SubRecords with their respective occurrences
* @return The described value
*/
public HashMap<String, Integer> getSubRecords()
{
return subRecords;
}
/**
* Returns the date of birth as the String read in the file
* @return The described value.
*/
public String getDateOfBirth()
{
return dateOfBirthString;
}
/**
* Returns the date of birth split into 3 parts (day, month, year)
* @return the described value
*/
public HashMap<String, Integer> getSplitDateOfBirth()
{
HashMap<String, Integer> res= new HashMap<>();
if(getDateOfBirthDay()>0)
{
res.put(Text.DAY, getDateOfBirthDay());
}
if(getDateOfBirthMonth()>0)
{
res.put(Text.MONTH, getDateOfBirthMonth());
}
if(getDateOfBirthYear()>0)
{
res.put(Text.YEAR, getDateOfBirthYear());
}
return res;
}
/**
* Returns the biological sex as given in the file
* @return the described value
*/
public BiologicalSex getBSex()
{
return bSex;
}
}