diff --git a/gstlal/gst/lal/Makefile.am b/gstlal/gst/lal/Makefile.am
index 4394df2ef461751a2cfb2adbf2c69af9dee4f784..c1b10591dea318b4f98adae4e37b8e6296243283 100644
--- a/gstlal/gst/lal/Makefile.am
+++ b/gstlal/gst/lal/Makefile.am
@@ -27,5 +27,5 @@ lib@GSTPLUGINPREFIX@gstlal_la_SOURCES = \
 	gstlal_whiten.h gstlal_whiten.c \
 	gstlal_shift.h gstlal_shift.c
 lib@GSTPLUGINPREFIX@gstlal_la_CFLAGS = $(AM_CFLAGS) $(GSL_CFLAGS) $(FFTW_CFLAGS) $(LAL_CFLAGS) $(gstreamer_CFLAGS) $(gstreamer_audio_CFLAGS)
-lib@GSTPLUGINPREFIX@gstlal_la_LIBADD = $(top_builddir)/lib/gstlal/libgstlal.la $(top_builddir)/lib/gstlal/libgstlaltags.la $(top_builddir)/lib/gstlal/libgstlaltypes.la
+lib@GSTPLUGINPREFIX@gstlal_la_LIBADD = $(top_builddir)/lib/gstlal/libezligolw.la $(top_builddir)/lib/gstlal/libgstlal.la $(top_builddir)/lib/gstlal/libgstlaltags.la $(top_builddir)/lib/gstlal/libgstlaltypes.la
 lib@GSTPLUGINPREFIX@gstlal_la_LDFLAGS = $(AM_LDFLAGS) $(GSL_LIBS) $(FFTW_LIBS) $(LAL_LIBS) $(gstreamer_LIBS) $(gstreamer_audio_LIBS) $(GSTLAL_PLUGIN_LDFLAGS)
diff --git a/gstlal/gst/lal/gstlal_simulation.c b/gstlal/gst/lal/gstlal_simulation.c
index 00b8740f0d1e39abb0224f223be5f2f022afd496..4439c585c25a39a696101d1e6e5384b13e71a76c 100644
--- a/gstlal/gst/lal/gstlal_simulation.c
+++ b/gstlal/gst/lal/gstlal_simulation.c
@@ -65,19 +65,20 @@
  */
 
 
+#include <lal/Date.h>
+#include <lal/FindChirp.h>
+#include <lal/FrequencySeries.h>
+#include <lal/GenerateBurst.h>
 #include <lal/LALConfig.h>
 #include <lal/LALDatatypes.h>
-#include <lal/LALStdlib.h>
-#include <lal/LALSimulation.h>
 #include <lal/LALSimInspiral.h>
+#include <lal/LALSimulation.h>
+#include <lal/LALStdlib.h>
+#include <lal/LIGOLwXML.h>
+#include <lal/LIGOMetadataTables.h>
+#include <lal/LIGOMetadataUtils.h>
 #include <lal/SnglBurstUtils.h>
-#include <lal/LIGOLwXMLBurstRead.h>
-#include <lal/LIGOLwXMLInspiralRead.h>
-#include <lal/GenerateBurst.h>
-#include <lal/FindChirp.h>
-#include <lal/Date.h>
 #include <lal/TimeSeries.h>
-#include <lal/FrequencySeries.h>
 #include <lal/Units.h>
 
 
@@ -86,6 +87,7 @@
  */
 
 
+#include <gstlal/ezligolw.h>
 #include <gstlal/gstlal.h>
 #include <gstlal/gstlal_tags.h>
 #include <gstlal_simulation.h>
@@ -148,11 +150,224 @@ static void destroy_injection_document(struct injection_document *doc)
  */
 
 
+static int sim_burst_row_callback(struct ligolw_table *table, struct ligolw_table_row row, void *data)
+{
+	int result_code;
+	SimBurst **head = data;
+	SimBurst *new = XLALCreateSimBurst();
+	struct ligolw_unpacking_spec spec[] = {
+		{&new->process_id, "process_id", ligolw_cell_type_int_8s, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, "waveform", ligolw_cell_type_lstring, LIGOLW_UNPACKING_REQUIRED},
+		{&new->ra, "ra", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->dec, "dec", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->psi, "psi", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->time_geocent_gps.gpsSeconds, "time_geocent_gps", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		{&new->time_geocent_gps.gpsNanoSeconds, "time_geocent_gps_ns", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		{&new->time_geocent_gmst, "time_geocent_gmst", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->duration, "duration", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->frequency, "frequency", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->bandwidth, "bandwidth", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->q, "q", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->pol_ellipse_angle, "pol_ellipse_angle", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->pol_ellipse_e, "pol_ellipse_e", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->amplitude, "amplitude", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->hrss, "hrss", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->egw_over_rsquared, "egw_over_rsquared", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{&new->waveform_number, "waveform_number", ligolw_cell_type_int_8u, LIGOLW_UNPACKING_REQUIRED},
+		{&new->time_slide_id, "time_slide_id", ligolw_cell_type_int_8s, LIGOLW_UNPACKING_REQUIRED},
+		{&new->simulation_id, "simulation_id", ligolw_cell_type_int_8s, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, NULL, -1, 0}
+	};
+
+	/* check for memory allocation failure.  remember to clean up row's
+	 * memory. */
+	if(!new) {
+		XLALPrintError("memory allocation failure\n");
+		free(row.cells);
+		return -1;
+	}
+
+	/* unpack.  have to do the strings manually because they get copied
+	 * by value rather than reference.  ligolw_unpacking_row_builder()
+	 * cleans up row's memory for us. */
+	strncpy(new->waveform, ligolw_row_get_cell(row, "waveform").as_string, LIGOMETA_WAVEFORM_MAX - 1);
+	new->waveform[LIGOMETA_WAVEFORM_MAX - 1] = '\0';
+
+	result_code = ligolw_unpacking_row_builder(table, row, spec);
+	if(result_code > 0) {
+		/* missing required column */
+		XLALPrintError("failure parsing row: missing column \"%s\"\n", spec[result_code - 1].name);
+		free(new);
+		return -1;
+	} else if(result_code < 0) {
+		/* column type mismatch */
+		XLALPrintError("failure parsing row: incorrect type for column \"%s\"\n", spec[-result_code - 1].name);
+		free(new);
+		return -1;
+	}
+
+	/* add new sim to head of linked list.  yes, this means the table's
+	 * rows get reversed.  so what. */
+	new->next = *head;
+	*head = new;
+
+	/* success */
+	return 0;
+}
+
+
+static int time_slide_row_callback(struct ligolw_table *table, struct ligolw_table_row row, void *data)
+{
+	int result_code;
+	TimeSlide **head = data;
+	TimeSlide *new = XLALCreateTimeSlide();
+	struct ligolw_unpacking_spec spec[] = {
+		{&new->process_id, "process_id", ligolw_cell_type_int_8s, LIGOLW_UNPACKING_REQUIRED},
+		{&new->time_slide_id, "time_slide_id", ligolw_cell_type_int_8s, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, "instrument", ligolw_cell_type_lstring, LIGOLW_UNPACKING_REQUIRED},
+		{&new->offset, "offset", ligolw_cell_type_real_8, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, NULL, -1, 0}
+	};
+
+	/* check for memory allocation failure.  remember to clean up row's
+	 * memory. */
+	if(!new) {
+		XLALPrintError("memory allocation failure\n");
+		free(row.cells);
+		return -1;
+	}
+
+	/* unpack.  have to do the strings manually because they get copied
+	 * by value rather than reference.  ligolw_unpacking_row_builder()
+	 * cleans up row's memory for us. */
+	strncpy(new->instrument, ligolw_row_get_cell(row, "instrument").as_string, LIGOMETA_STRING_MAX - 1);
+	new->instrument[LIGOMETA_WAVEFORM_MAX - 1] = '\0';
+
+	result_code = ligolw_unpacking_row_builder(table, row, spec);
+	if(result_code > 0) {
+		/* missing required column */
+		XLALPrintError("failure parsing row: missing column \"%s\"\n", spec[result_code - 1].name);
+		free(new);
+		return -1;
+	} else if(result_code < 0) {
+		/* column type mismatch */
+		XLALPrintError("failure parsing row: incorrect type for column \"%s\"\n", spec[-result_code - 1].name);
+		free(new);
+		return -1;
+	}
+
+	/* add new sim to head of linked list.  yes, this means the table's
+	 * rows get reversed.  so what. */
+	new->next = *head;
+	*head = new;
+
+	/* success */
+	return 0;
+}
+
+
+static int sim_inspiral_row_callback(struct ligolw_table *table, struct ligolw_table_row row, void *data)
+{
+	int result_code;
+	SimInspiralTable **head = data;
+	SimInspiralTable *new = LALCalloc(1, sizeof(*new));	/* ugh, lal */
+	struct ligolw_unpacking_spec spec[] = {
+		{&new->process_id, "process_id", ligolw_cell_type_int_8s, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, "waveform", ligolw_cell_type_lstring, LIGOLW_UNPACKING_REQUIRED},
+		{&new->geocent_end_time.gpsSeconds, "geocent_end_time", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		{&new->geocent_end_time.gpsNanoSeconds, "geocent_end_time_ns", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		/* don't load detector end times:  they're stupid */
+		{NULL, "source", ligolw_cell_type_lstring, LIGOLW_UNPACKING_REQUIRED},
+		{&new->mass1, "mass1", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->mass2, "mass2", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->mchirp, "mchirp", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->eta, "eta", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->distance, "distance", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->longitude, "longitude", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->latitude, "latitude", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->inclination, "inclination", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->coa_phase, "coa_phase", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->polarization, "polarization", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->psi0, "psi0", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->psi3, "psi3", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->alpha, "alpha", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->alpha1, "alpha1", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->alpha2, "alpha2", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->alpha3, "alpha3", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->alpha4, "alpha4", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->alpha5, "alpha5", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->alpha6, "alpha6", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->beta, "beta", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->spin1x, "spin1x", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->spin1y, "spin1y", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->spin1z, "spin1z", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->spin2x, "spin2x", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->spin2y, "spin2y", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->spin2z, "spin2z", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->theta0, "theta0", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->phi0, "phi0", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->f_lower, "f_lower", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		{&new->f_final, "f_final", ligolw_cell_type_real_4, LIGOLW_UNPACKING_REQUIRED},
+		/* don't load effective distances:  they're stupid */
+		{&new->numrel_mode_min, "numrel_mode_min", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		{&new->numrel_mode_max, "numrel_mode_max", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, "numrel_data", ligolw_cell_type_lstring, LIGOLW_UNPACKING_REQUIRED},
+		{&new->amp_order, "amp_order", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, "taper", ligolw_cell_type_lstring, LIGOLW_UNPACKING_REQUIRED},
+		{&new->bandpass, "bandpass", ligolw_cell_type_int_4s, LIGOLW_UNPACKING_REQUIRED},
+		{&new->simulation_id, "simulation_id", ligolw_cell_type_int_8s, LIGOLW_UNPACKING_REQUIRED},
+		{NULL, NULL, -1, 0}
+	};
+
+	/* check for memory allocation failure.  remember to clean up row's
+	 * memory. */
+	if(!new) {
+		XLALPrintError("memory allocation failure\n");
+		free(row.cells);
+		return -1;
+	}
+
+	/* unpack.  have to do the strings manually because they get copied
+	 * by value rather than reference.  ligolw_unpacking_row_builder()
+	 * cleans up row's memory for us. */
+	strncpy(new->waveform, ligolw_row_get_cell(row, "waveform").as_string, LIGOMETA_WAVEFORM_MAX - 1);
+	new->waveform[LIGOMETA_WAVEFORM_MAX - 1] = '\0';
+	strncpy(new->source, ligolw_row_get_cell(row, "source").as_string, LIGOMETA_SOURCE_MAX - 1);
+	new->source[LIGOMETA_SOURCE_MAX - 1] = '\0';
+	strncpy(new->numrel_data, ligolw_row_get_cell(row, "numrel_data").as_string, LIGOMETA_STRING_MAX - 1);
+	new->numrel_data[LIGOMETA_STRING_MAX - 1] = '\0';
+	strncpy(new->taper, ligolw_row_get_cell(row, "taper").as_string, LIGOMETA_INSPIRALTAPER_MAX - 1);
+	new->taper[LIGOMETA_INSPIRALTAPER_MAX - 1] = '\0';
+
+	result_code = ligolw_unpacking_row_builder(table, row, spec);
+	if(result_code > 0) {
+		/* missing required column */
+		XLALPrintError("failure parsing row: missing column \"%s\"\n", spec[result_code - 1].name);
+		LALFree(new);
+		return -1;
+	} else if(result_code < 0) {
+		/* column type mismatch */
+		XLALPrintError("failure parsing row: incorrect type for column \"%s\"\n", spec[-result_code - 1].name);
+		LALFree(new);
+		return -1;
+	}
+
+	/* add new sim to head of linked list.  yes, this means the table's
+	 * rows get reversed.  so what. */
+	new->next = *head;
+	*head = new;
+
+	/* success */
+	return 0;
+}
+
+
 static struct injection_document *load_injection_document(const char *filename, LIGOTimeGPS start, LIGOTimeGPS end, double longest_injection)
 {
-	int success = 1;
+	ezxml_t xmldoc;
+	ezxml_t elem;
+	struct ligolw_table *table;
 	struct injection_document *new;
-	int nrows; 
 
 	g_assert(filename != NULL);
 
@@ -163,7 +378,7 @@ static struct injection_document *load_injection_document(const char *filename,
 	new = g_new0(struct injection_document, 1);
 	if(!new) {
 		XLALPrintError("%s(): malloc() failed\n", __func__);
-		XLAL_ERROR_NULL(XLAL_ENOMEM);
+		goto allocfailed;
 	}
 
 	/*
@@ -173,101 +388,94 @@ static struct injection_document *load_injection_document(const char *filename,
 	XLALGPSAdd(&start, -longest_injection);
 	XLALGPSAdd(&end, longest_injection);
 
+	/* parse the document */
+	xmldoc = ezxml_parse_file(filename);
+	if(!xmldoc) {
+		XLALPrintError("%s(): error parsing \"%s\"\n", __func__, filename);
+		goto parsefailed;
+	}
+
 	/*
-	 * load optional sim_burst and time_slide table
+	 * load optional (sim_burst + time_slide) tables
 	 */
 
-	new->has_sim_burst_table = XLALLIGOLwHasTable(filename, "sim_burst");
-	if(new->has_sim_burst_table < 0) {
-		XLALPrintError("%s(): error searching for sim_burst table in \"%s\": %s\n", __func__, filename, XLALErrorString(xlalErrno));
-		XLALClearErrno();
+	elem = ligolw_table_get(xmldoc, "sim_burst");
+	if(elem) {
+		table = ligolw_table_parse(elem, sim_burst_row_callback, &new->sim_burst_table_head);
+		if(!table) {
+			XLALPrintError("%s(): failure parsing sim_burst table in \"%s\"\n", __func__, filename);
+			goto simburstfailed;
+		}
+		ligolw_table_free(table);
+		new->has_sim_burst_table = 1;
+	} else {
 		new->has_sim_burst_table = 0;
 		new->sim_burst_table_head = NULL;
-		success = 0;
-	} else if(new->has_sim_burst_table) {
-		XLALClearErrno();
-		new->sim_burst_table_head = XLALSimBurstTableFromLIGOLw(filename, &start, &end);
-		if(XLALGetBaseErrno()) {
-			XLALPrintError("%s(): failure reading sim_burst table from \"%s\"\n", __func__, filename);
-			success = 0;
-		} else
-			XLALPrintInfo("%s(): found sim_burst table\n", __func__);
-	} else
-		new->sim_burst_table_head = NULL;
+	}
 
-	new->has_time_slide_table = XLALLIGOLwHasTable(filename, "time_slide");
-	if(new->has_time_slide_table < 0) {
-		XLALPrintError("%s(): error searching for time_slide table in \"%s\": %s\n", __func__, filename, XLALErrorString(xlalErrno));
-		XLALClearErrno();
+	elem = ligolw_table_get(xmldoc, "time_slide");
+	if(elem) {
+		table = ligolw_table_parse(elem, time_slide_row_callback, &new->time_slide_table_head);
+		if(!table) {
+			XLALPrintError("%s(): failure parsing time_slide table in \"%s\"\n", __func__, filename);
+			goto timeslidefailed;
+		}
+		ligolw_table_free(table);
+		new->has_time_slide_table = 1;
+	} else if(new->has_sim_burst_table) {
+		/* document is required to have a time_slide table if it
+		 * has a sim_burst table */
+		XLALPrintError("%s(): sim_burst table requires time_slide table in \"%s\"\n", __func__, filename);
+		goto timeslidefailed;
+	} else {
 		new->has_time_slide_table = 0;
 		new->time_slide_table_head = NULL;
-		success = 0;
-	} else if(new->has_time_slide_table) {
-		XLALClearErrno();
-		new->time_slide_table_head = XLALTimeSlideTableFromLIGOLw(filename);
-		if(XLALGetBaseErrno()) {
-			XLALPrintError("%s(): failure reading time_slide table from \"%s\"\n", __func__, filename);
-			success = 0;
-		} else
-			XLALPrintInfo("%s(): found time_slide table\n", __func__);
-	} else
-		new->time_slide_table_head = NULL;
-
-	/*
-	 * skipping burst injections if no time_slide table present
-	 */
-
-	if(new->has_sim_burst_table && !new->has_time_slide_table) {
-		XLALPrintWarning("%s(): Skipping burst injections since \"%s\" must contain a time_slide table for them.\n", __func__, filename);
-		XLALDestroySimBurstTable(new->sim_burst_table_head);
-		new->sim_burst_table_head = NULL;
 	}
 
 	/*
-	 * load optional sim_inspiral table
+	 * load optional sim_inspiral table.  subsequent code requires it
+	 * to be ordered by geocenter end time.
 	 */
 
-	new->has_sim_inspiral_table = XLALLIGOLwHasTable(filename, "sim_inspiral");
-	if(new->has_sim_inspiral_table < 0) {
-		XLALPrintError("%s(): error searching for sim_inspiral table in \"%s\": %s\n", __func__, filename, XLALErrorString(xlalErrno));
-		XLALClearErrno();
-		new->has_sim_inspiral_table = 0;
-		new->sim_inspiral_table_head = NULL;
-		success = 0;
-	} else if(new->has_sim_inspiral_table) {
-		new->sim_inspiral_table_head = NULL;
-		/* FIXME: we need a smarter way to load the injections. We want to pick up injections that have an end_time
-		 * after end if the beginning of the waveform starts before end.
-		 */
-		nrows = SimInspiralTableFromLIGOLw(&new->sim_inspiral_table_head, filename, start.gpsSeconds - 1, end.gpsSeconds + 1);
-		if(nrows < 0) {
-			XLALPrintError("%s(): failure reading sim_inspiral table from \"%s\"\n", __func__, filename);
-			new->sim_inspiral_table_head = NULL;
-			success = 0;
-		} else {
-			/* FIXME no rows found raises an error we don't care about, but why ? */
-			XLALPrintInfo("%s(): found sim_inspiral table\n", __func__);
-			XLALClearErrno();
+	elem = ligolw_table_get(xmldoc, "sim_inspiral");
+	if(elem) {
+		table = ligolw_table_parse(elem, sim_inspiral_row_callback, &new->sim_inspiral_table_head);
+		if(!table) {
+			XLALPrintError("%s(): failure parsing sim_inspiral table in \"%s\"\n", __func__, filename);
+			goto siminspiralfailed;
 		}
+		ligolw_table_free(table);
+		new->has_sim_inspiral_table = 1;
 		XLALSortSimInspiral(&new->sim_inspiral_table_head, XLALCompareSimInspiralByGeocentEndTime);
-	} else
+	} else {
+		new->has_sim_inspiral_table = 0;
 		new->sim_inspiral_table_head = NULL;
+	}
 
 	/*
-	 * did we get it all?
+	 * clean up
 	 */
 
-	if(!success) {
-		XLALPrintError("%s(): document is incomplete and/or malformed reading \"%s\"\n", __func__, filename);
-		destroy_injection_document(new);
-		XLAL_ERROR_NULL(XLAL_EFUNC);
-	}
+	ezxml_free(xmldoc);
 
 	/*
 	 * success
 	 */
 
 	return new;
+
+	/*
+	 * error
+	 */
+
+siminspiralfailed:
+timeslidefailed:
+simburstfailed:
+	ezxml_free(xmldoc);
+parsefailed:
+allocfailed:
+	destroy_injection_document(new);
+	return NULL;
 }