package ca.uhn.fhir.tests.integration.karaf.dstu21;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.LenientErrorHandler;
import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.rest.api.Constants;
import com.google.common.collect.Sets;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hamcrest.text.StringContainsInOrder;
import org.hl7.fhir.dstu2016may.model.Address;
import org.hl7.fhir.dstu2016may.model.Appointment;
import org.hl7.fhir.dstu2016may.model.AuditEvent;
import org.hl7.fhir.dstu2016may.model.Binary;
import org.hl7.fhir.dstu2016may.model.Bundle;
import org.hl7.fhir.dstu2016may.model.CodeType;
import org.hl7.fhir.dstu2016may.model.CodeableConcept;
import org.hl7.fhir.dstu2016may.model.Coding;
import org.hl7.fhir.dstu2016may.model.Condition;
import org.hl7.fhir.dstu2016may.model.ContactPoint;
import org.hl7.fhir.dstu2016may.model.DateTimeType;
import org.hl7.fhir.dstu2016may.model.DateType;
import org.hl7.fhir.dstu2016may.model.DiagnosticReport;
import org.hl7.fhir.dstu2016may.model.DocumentManifest;
import org.hl7.fhir.dstu2016may.model.Duration;
import org.hl7.fhir.dstu2016may.model.Encounter;
import org.hl7.fhir.dstu2016may.model.Enumerations;
import org.hl7.fhir.dstu2016may.model.Extension;
import org.hl7.fhir.dstu2016may.model.HumanName;
import org.hl7.fhir.dstu2016may.model.IdType;
import org.hl7.fhir.dstu2016may.model.Identifier;
import org.hl7.fhir.dstu2016may.model.InstantType;
import org.hl7.fhir.dstu2016may.model.Location;
import org.hl7.fhir.dstu2016may.model.Medication;
import org.hl7.fhir.dstu2016may.model.MedicationOrder;
import org.hl7.fhir.dstu2016may.model.Observation;
import org.hl7.fhir.dstu2016may.model.Organization;
import org.hl7.fhir.dstu2016may.model.Patient;
import org.hl7.fhir.dstu2016may.model.PrimitiveType;
import org.hl7.fhir.dstu2016may.model.Quantity;
import org.hl7.fhir.dstu2016may.model.Reference;
import org.hl7.fhir.dstu2016may.model.Resource;
import org.hl7.fhir.dstu2016may.model.SampledData;
import org.hl7.fhir.dstu2016may.model.SimpleQuantity;
import org.hl7.fhir.dstu2016may.model.StringType;
import org.hl7.fhir.dstu2016may.model.UriType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import org.xmlunit.builder.DiffBuilder;
import org.xmlunit.builder.Input;
import org.xmlunit.diff.ComparisonControllers;
import org.xmlunit.diff.DefaultNodeMatcher;
import org.xmlunit.diff.Diff;
import org.xmlunit.diff.ElementSelectors;

import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_DSTU2_1;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;


/**
 * Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
 */
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class XmlParserDstu2_1Test {

	private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2_1Test.class);
	private FhirContext ourCtx = FhirContext.forDstu2_1();

   @Configuration
   public Option[] config() throws IOException {
      return options(
      	KARAF.option(),
			WRAP.option(),
			HAPI_FHIR_DSTU2_1.option(),
		   mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
			mavenBundle().groupId("org.xmlunit").artifactId("xmlunit-core").versionAsInProject(),
			when(false)
         	.useOptions(
            	debugConfiguration("5005", true))
      );
   }

	@Test
	public void testOverrideResourceIdWithBundleEntryFullUrlDisabled_ConfiguredOnFhirContext() {
		try {
			String tmp = "<Bundle xmlns=\"http://hl7.org/fhir\"><entry><fullUrl value=\"http://lalaland.org/patient/pat1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"patxuzos\"/></Patient></resource></entry></Bundle>";
			ourCtx.getParserOptions().setOverrideResourceIdWithBundleEntryFullUrl(false);
			Bundle bundle = (Bundle) ourCtx.newXmlParser().parseResource(tmp);
			assertEquals(1, bundle.getEntry().size());
			{
				Patient o1 = (Patient) bundle.getEntry().get(0).getResource();
				IIdType o1Id = o1.getIdElement();
				assertFalse(o1Id.hasBaseUrl());
				assertEquals("Patient", o1Id.getResourceType());
				assertEquals("patxuzos", o1Id.getIdPart());
				assertFalse(o1Id.hasVersionIdPart());
			}
		} finally {
			// ensure we cleanup ourCtx so other tests continue to work
			ourCtx = null;
		}
	}

	@Test
	public void testOverrideResourceIdWithBundleEntryFullUrlDisabled_ConfiguredOnParser() {
		try {
			String tmp = "<Bundle xmlns=\"http://hl7.org/fhir\"><entry><fullUrl value=\"http://lalaland.org/patient/pat1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"patxuzos\"/></Patient></resource></entry></Bundle>";
			Bundle bundle = (Bundle) ourCtx.newXmlParser().setOverrideResourceIdWithBundleEntryFullUrl(false).parseResource(tmp);
			assertEquals(1, bundle.getEntry().size());
			{
				Patient o1 = (Patient) bundle.getEntry().get(0).getResource();
				IIdType o1Id = o1.getIdElement();
				assertFalse(o1Id.hasBaseUrl());
				assertEquals("Patient", o1Id.getResourceType());
				assertEquals("patxuzos", o1Id.getIdPart());
				assertFalse(o1Id.hasVersionIdPart());
			}
		} finally {
			// ensure we cleanup ourCtx so other tests continue to work
			ourCtx = null;
		}
	}

	/**
	 * See #414
	 */
	@Test
	public void testParseXmlExtensionWithoutUrl() {
		//@formatter:off
		String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"        <extension>\n" +
			"          <valueDateTime value=\"2011-01-02T11:13:15\"/>\n" +
			"        </extension>\n" +
			"</Patient>";
		//@formatter:on

		IParser parser = ourCtx.newXmlParser();
		parser.setParserErrorHandler(new LenientErrorHandler());
		Patient parsed = (Patient) parser.parseResource(input);
		assertEquals(1, parsed.getExtension().size());
		assertEquals(null, parsed.getExtension().get(0).getUrl());
		assertEquals("2011-01-02T11:13:15", ((PrimitiveType<?>)parsed.getExtension().get(0).getValue()).getValueAsString());

		try {
			parser = ourCtx.newXmlParser();
			parser.setParserErrorHandler(new StrictErrorHandler());
			parser.parseResource(input);
			fail();
		} catch (DataFormatException e) {
			assertEquals("Resource is missing required element 'url' in parent element 'extension'", e.getCause().getMessage());
		}

	}


	/**
	 * See #414
	 */
	@Test
	public void testParseXmlModifierExtensionWithoutUrl() {
		//@formatter:off
		String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"        <modifierExtension>\n" +
			"          <valueDateTime value=\"2011-01-02T11:13:15\"/>\n" +
			"        </modifierExtension>\n" +
			"</Patient>";
		//@formatter:on

		IParser parser = ourCtx.newXmlParser();
		parser.setParserErrorHandler(new LenientErrorHandler());
		Patient parsed = (Patient) parser.parseResource(input);
		assertEquals(1, parsed.getModifierExtension().size());
		assertEquals(null, parsed.getModifierExtension().get(0).getUrl());
		assertEquals("2011-01-02T11:13:15", ((PrimitiveType<?>)parsed.getModifierExtension().get(0).getValue()).getValueAsString());

		try {
			parser = ourCtx.newXmlParser();
			parser.setParserErrorHandler(new StrictErrorHandler());
			parser.parseResource(input);
			fail();
		} catch (DataFormatException e) {
			assertEquals("Resource is missing required element 'url' in parent element 'modifierExtension'", e.getCause().getMessage());
		}

	}

	@Test
	public void testEncodeChainedContainedResourcer() {
		Organization gp = new Organization();
		gp.setName("grandparent");

		Organization parent = new Organization();
		parent.setName("parent");
		parent.getPartOf().setResource(gp);

		Organization child = new Organization();
		child.setName("child");
		child.getPartOf().setResource(parent);

		Patient patient = new Patient();
		patient.getManagingOrganization().setResource(child);

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
		ourLog.info(encoded);

		patient = ourCtx.newXmlParser().parseResource(Patient.class, encoded);

		child = (Organization) patient.getManagingOrganization().getResource();
		assertEquals("child", child.getName());

		parent = (Organization) child.getPartOf().getResource();
		assertEquals("parent", parent.getName());

		gp = (Organization) parent.getPartOf().getResource();
		assertEquals("grandparent", gp.getName());
	}

	@Test
	public void testBundleWithBinary() {
		//@formatter:off
		String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"   <base value=\"http://localhost:52788\"/>\n" +
			"   <total value=\"1\"/>\n" +
			"   <link>\n" +
			"      <relation value=\"self\"/>\n" +
			"      <url value=\"http://localhost:52788/Binary?_pretty=true\"/>\n" +
			"   </link>\n" +
			"   <entry>\n" +
			"      <resource>\n" +
			"         <Binary xmlns=\"http://hl7.org/fhir\">\n" +
			"            <id value=\"1\"/>\n" +
			"            <meta/>\n" +
			"            <contentType value=\"text/plain\"/>\n" +
			"            <content value=\"AQIDBA==\"/>\n" +
			"         </Binary>\n" +
			"      </resource>\n" +
			"   </entry>\n" +
			"</Bundle>";
		//@formatter:on

		Bundle b = ourCtx.newXmlParser().parseResource(Bundle.class, bundle);
		assertEquals(1, b.getEntry().size());

		Binary bin = (Binary) b.getEntry().get(0).getResource();
		assertArrayEquals(new byte[] { 1, 2, 3, 4 }, bin.getContent());

	}

	@Test
	public void testContainedResourceInExtensionUndeclared() {
		Patient p = new Patient();
		p.addName().addFamily("PATIENT");

		Organization o = new Organization();
		o.setName("ORG");
		p.addExtension(new Extension("urn:foo", new Reference(o)));

		String str = ourCtx.newXmlParser().encodeResourceToString(p);
		ourLog.info(str);

		p = ourCtx.newXmlParser().parseResource(Patient.class, str);
		assertEquals("PATIENT", p.getName().get(0).getFamilyAsSingleString());

		List<Extension> exts = p.getExtensionsByUrl("urn:foo");
		assertEquals(1, exts.size());
		Reference rr = (Reference) exts.get(0).getValue();
		o = (Organization) rr.getResource();
		assertEquals("ORG", o.getName());
	}

	@Test
	public void testDuration() {
		Encounter enc = new Encounter();
		Duration duration = new Duration();
		duration.setUnit("day").setValue(123L);
		enc.setLength(duration);

		String str = ourCtx.newXmlParser().encodeResourceToString(enc);
		ourLog.info(str);

		assertThat(str, not(containsString("meta")));
		assertThat(str, containsString("<length><value value=\"123\"/><unit value=\"day\"/></length>"));
	}

	@Test
	public void testEncodeAndParseBundleWithResourceRefs() {

		Patient pt = new Patient();
		pt.setId("patid");
		pt.addName().addFamily("PATIENT");

		Organization org = new Organization();
		org.setId("orgid");
		org.setName("ORG");
		pt.getManagingOrganization().setResource(org);

		Bundle bundle = new Bundle();
		bundle.addEntry().setResource(pt);
		bundle.addEntry().setResource(org);

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle);
		ourLog.info(encoded);

		//@formatter:off
		assertThat(encoded, stringContainsInOrder(
			"<Patient xmlns=\"http://hl7.org/fhir\">",
			"<managingOrganization>",
			"<reference value=\"Organization/orgid\"/>",
			"</managingOrganization>"
		));
		//@formatter:on

		bundle = ourCtx.newXmlParser().parseResource(Bundle.class, encoded);
		pt = (Patient) bundle.getEntry().get(0).getResource();
		org = (Organization) bundle.getEntry().get(1).getResource();

		assertEquals("Organization/orgid", org.getIdElement().getValue());
		assertEquals("Organization/orgid", pt.getManagingOrganization().getReferenceElement().getValue());
		assertSame(org, pt.getManagingOrganization().getResource());
	}

	@Test
	public void testEncodeAndParseContained() {
		IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);

		// Create an organization, note that the organization does not have an ID
		Organization org = new Organization();
		org.getNameElement().setValue("Contained Test Organization");

		// Create a patient
		Patient patient = new Patient();
		patient.setId("Patient/1333");
		patient.addIdentifier().setSystem("urn:mrns").setValue("253345");

		// Put the organization as a reference in the patient resource
		patient.getManagingOrganization().setResource(org);

		String encoded = xmlParser.encodeResourceToString(patient);
		ourLog.info(encoded);
		assertThat(encoded, containsString("<contained>"));
		assertThat(encoded, containsString("<reference value=\"#1\"/>"));

		// Create a bundle with just the patient resource
		Bundle b = new Bundle();
		b.addEntry().setResource(patient);

		// Encode the bundle
		encoded = xmlParser.encodeResourceToString(b);
		ourLog.info(encoded);
		assertThat(encoded, stringContainsInOrder(Arrays.asList("<contained>", "<id value=\"1\"/>", "</contained>")));
		assertThat(encoded, containsString("<reference value=\"#1\"/>"));
		assertThat(encoded, stringContainsInOrder(Arrays.asList("<entry>", "</entry>")));
		assertThat(encoded, not(stringContainsInOrder(Arrays.asList("<entry>", "</entry>", "<entry>"))));

		// Re-parse the bundle
		patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient));
		assertEquals("#1", patient.getManagingOrganization().getReference());

		assertNotNull(patient.getManagingOrganization().getResource());
		org = (Organization) patient.getManagingOrganization().getResource();
		assertEquals("#1", org.getIdElement().getValue());
		assertEquals("Contained Test Organization", org.getName());

		// And re-encode a second time
		encoded = xmlParser.encodeResourceToString(patient);
		ourLog.info(encoded);
		assertThat(encoded, stringContainsInOrder(Arrays.asList("<contained>", "<Organization ", "<id value=\"1\"/>", "</Organization", "</contained>", "<reference value=\"#1\"/>")));
		assertThat(encoded, not(stringContainsInOrder(Arrays.asList("<contained>", "<Org", "<contained>"))));
		assertThat(encoded, containsString("<reference value=\"#1\"/>"));

		// And re-encode once more, with the references cleared
		patient.getContained().clear();
		patient.getManagingOrganization().setReference((String) null);
		encoded = xmlParser.encodeResourceToString(patient);
		ourLog.info(encoded);
		assertThat(encoded, stringContainsInOrder(Arrays.asList("<contained>", "<Organization ", "<id value=\"1\"/>", "</Organization", "</contained>", "<reference value=\"#1\"/>")));
		assertThat(encoded, not(stringContainsInOrder(Arrays.asList("<contained>", "<Org", "<contained>"))));
		assertThat(encoded, containsString("<reference value=\"#1\"/>"));

		// And re-encode once more, with the references cleared and a manually set local ID
		patient.getContained().clear();
		patient.getManagingOrganization().setReference((String) null);
		patient.getManagingOrganization().getResource().setId(("#333"));
		encoded = xmlParser.encodeResourceToString(patient);
		ourLog.info(encoded);
		assertThat(encoded, stringContainsInOrder(Arrays.asList("<contained>", "<Organization ", "<id value=\"333\"/>", "</Organization", "</contained>", "<reference value=\"#333\"/>")));
		assertThat(encoded, not(stringContainsInOrder(Arrays.asList("<contained>", "<Org", "<contained>"))));

	}

	@Test
	public void testEncodeAndParseContainedNonCustomTypes() {
		ourCtx = FhirContext.forDstu2_1();

		Observation obs = new Observation();
		obs.setStatus(Observation.ObservationStatus.FINAL);

		DiagnosticReport dr = new DiagnosticReport();
		dr.setStatus(DiagnosticReport.DiagnosticReportStatus.FINAL);
		dr.addResult().setResource(obs);

		IParser parser = ourCtx.newXmlParser();
		parser.setPrettyPrint(true);

		String output = parser.encodeResourceToString(dr);
		ourLog.info(output);

		//@formatter:off
		assertThat(output,stringContainsInOrder(
			"<DiagnosticReport xmlns=\"http://hl7.org/fhir\">",
			"<contained>",
			"<Observation xmlns=\"http://hl7.org/fhir\">",
			"<id value=\"1\"/>",
			"<status value=\"final\"/>",
			"</Observation>",
			"</contained>",
			"<status value=\"final\"/>",
			"<result>",
			"<reference value=\"#1\"/>",
			"</result>",
			"</DiagnosticReport>"));
		//@formatter:on

	/*
	 * Now PARSE!
	 */

		dr = (DiagnosticReport) parser.parseResource(output);
		assertEquals(DiagnosticReport.DiagnosticReportStatus.FINAL, dr.getStatus());

		assertEquals("#1", dr.getResult().get(0).getReference());
		obs = (Observation) dr.getResult().get(0).getResource();
		assertEquals(Observation.ObservationStatus.FINAL, obs.getStatus());

		ourCtx = null;
	}

	@Test
	public void testEncodeAndParseExtensionOnCode() {
		Organization o = new Organization();
		o.setName("ORG");
		o.addExtension(new Extension("urn:foo", new CodeType("acode")));

		String str = ourCtx.newXmlParser().encodeResourceToString(o);
		ourLog.info(str);
		assertThat(str, containsString("<valueCode value=\"acode\"/>"));

		o = ourCtx.newXmlParser().parseResource(Organization.class, str);

		List<Extension> exts = o.getExtensionsByUrl("urn:foo");
		assertEquals(1, exts.size());
		CodeType code = (CodeType) exts.get(0).getValue();
		assertEquals("acode", code.getValue());

	}


	@Test
	public void testEncodeAndParseExtensions() throws Exception {

		Patient patient = new Patient();
		patient.addIdentifier().setUse(Identifier.IdentifierUse.OFFICIAL).setSystem("urn:example").setValue("7000135");

		Extension ext = new Extension();
		ext.setUrl("http://example.com/extensions#someext");
		ext.setValue(new DateTimeType("2011-01-02T11:13:15"));
		patient.addExtension(ext);

		Extension parent = new Extension().setUrl("http://example.com#parent");
		patient.addExtension(parent);
		Extension child1 = new Extension().setUrl("http://example.com#child").setValue(new StringType("value1"));
		parent.addExtension(child1);
		Extension child2 = new Extension().setUrl("http://example.com#child").setValue(new StringType("value2"));
		parent.addExtension(child2);

		Extension modExt = new Extension();
		modExt.setUrl("http://example.com/extensions#modext");
		modExt.setValue(new DateType("1995-01-02"));
		patient.addModifierExtension(modExt);

		HumanName name = patient.addName();
		name.addFamily("Blah");
		StringType given = name.addGivenElement();
		given.setValue("Joe");
		Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue(new StringType("given"));
		given.addExtension(ext2);

		StringType given2 = name.addGivenElement();
		given2.setValue("Shmoe");
		Extension given2ext = new Extension().setUrl("http://examples.com#givenext_parent");
		given2.addExtension(given2ext);
		given2ext.addExtension(new Extension().setUrl("http://examples.com#givenext_child").setValue(new StringType("CHILD")));

		String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
		ourLog.info(output);

		String enc = ourCtx.newXmlParser().encodeResourceToString(patient);
		assertThat(enc, containsString("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://example.com/extensions#someext\"><valueDateTime value=\"2011-01-02T11:13:15\"/></extension>"));
		assertThat(enc, containsString("<modifierExtension url=\"http://example.com/extensions#modext\"><valueDate value=\"1995-01-02\"/></modifierExtension>"));
		assertThat(enc, containsString(
			"<extension url=\"http://example.com#parent\"><extension url=\"http://example.com#child\"><valueString value=\"value1\"/></extension><extension url=\"http://example.com#child\"><valueString value=\"value2\"/></extension></extension>"));
		assertThat(enc, containsString("<given value=\"Joe\"><extension url=\"http://examples.com#givenext\"><valueString value=\"given\"/></extension></given>"));
		assertThat(enc, containsString(
			"<given value=\"Shmoe\"><extension url=\"http://examples.com#givenext_parent\"><extension url=\"http://examples.com#givenext_child\"><valueString value=\"CHILD\"/></extension></extension></given>"));

	/*
	 * Now parse this back
	 */

		Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, enc);
		ext = parsed.getExtension().get(0);
		assertEquals("http://example.com/extensions#someext", ext.getUrl());
		assertEquals("2011-01-02T11:13:15", ((DateTimeType) ext.getValue()).getValueAsString());

		parent = patient.getExtension().get(1);
		assertEquals("http://example.com#parent", parent.getUrl());
		assertNull(parent.getValue());
		child1 = parent.getExtension().get(0);
		assertEquals("http://example.com#child", child1.getUrl());
		assertEquals("value1", ((StringType) child1.getValue()).getValueAsString());
		child2 = parent.getExtension().get(1);
		assertEquals("http://example.com#child", child2.getUrl());
		assertEquals("value2", ((StringType) child2.getValue()).getValueAsString());

		modExt = parsed.getModifierExtension().get(0);
		assertEquals("http://example.com/extensions#modext", modExt.getUrl());
		assertEquals("1995-01-02", ((DateType) modExt.getValue()).getValueAsString());

		name = parsed.getName().get(0);

		ext2 = name.getGiven().get(0).getExtension().get(0);
		assertEquals("http://examples.com#givenext", ext2.getUrl());
		assertEquals("given", ((StringType) ext2.getValue()).getValueAsString());

		given2ext = name.getGiven().get(1).getExtension().get(0);
		assertEquals("http://examples.com#givenext_parent", given2ext.getUrl());
		assertNull(given2ext.getValue());
		Extension given2ext2 = given2ext.getExtension().get(0);
		assertEquals("http://examples.com#givenext_child", given2ext2.getUrl());
		assertEquals("CHILD", ((StringType) given2ext2.getValue()).getValue());

	}

	/**
	 * See #216
	 */
	@Test
	public void testEncodeAndParseIdentifierDstu2() {
		IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);

		Patient patient = new Patient();
		patient.addIdentifier().setSystem("SYS").setValue("VAL").setType(new CodeableConcept().addCoding(new Coding().setSystem("http://hl7.org/fhir/v2/0203").setCode("MR")));

		String out = xmlParser.encodeResourceToString(patient);
		ourLog.info(out);

		//@formatter:off
		assertThat(out, stringContainsInOrder("<identifier>",
			"<type>",
			"<coding>",
			"<system value=\"http://hl7.org/fhir/v2/0203\"/>",
			"<code value=\"MR\"/>",
			"</coding>",
			"</type>",
			"<system value=\"SYS\"/>",
			"<value value=\"VAL\"/>",
			"</identifier>"));
		//@formatter:on

		patient = ourCtx.newXmlParser().parseResource(Patient.class, out);
		assertEquals("http://hl7.org/fhir/v2/0203", patient.getIdentifier().get(0).getType().getCoding().get(0).getSystem());
		assertEquals("MR", patient.getIdentifier().get(0).getType().getCoding().get(0).getCode());
	}

	/**
	 * See #347
	 */
	@Test
	public void testEncodeAndParseMedicationOrder() {
		MedicationOrder mo = new MedicationOrder();
		mo.getDateWrittenElement().setValueAsString("2015-10-05");

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(mo);
		ourLog.info(encoded);

		mo = ourCtx.newXmlParser().parseResource(MedicationOrder.class, encoded);
		assertEquals("2015-10-05", mo.getDateWrittenElement().getValueAsString());
	}

	@Test
	public void testEncodeAndParseMetaProfileAndTags() {
		Patient p = new Patient();
		p.addName().addFamily("FAMILY");

		p.getMeta().addProfile("http://foo/Profile1");
		p.getMeta().addProfile("http://foo/Profile2");

		p.getMeta().addTag().setSystem("scheme1").setCode("term1").setDisplay("label1");
		p.getMeta().addTag().setSystem("scheme2").setCode("term2").setDisplay("label2");

		p.getMeta().addSecurity().setSystem("sec_scheme1").setCode("sec_term1").setDisplay("sec_label1");
		p.getMeta().addSecurity().setSystem("sec_scheme2").setCode("sec_term2").setDisplay("sec_label2");

		String enc = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
		ourLog.info(enc);

		//@formatter:off
		assertThat(enc, stringContainsInOrder("<Patient xmlns=\"http://hl7.org/fhir\">",
			"<meta>",
			"<profile value=\"http://foo/Profile1\"/>",
			"<profile value=\"http://foo/Profile2\"/>",
			"<tag>",
			"<system value=\"scheme1\"/>",
			"<code value=\"term1\"/>",
			"<display value=\"label1\"/>",
			"</tag>",
			"<tag>",
			"<system value=\"scheme2\"/>",
			"<code value=\"term2\"/>",
			"<display value=\"label2\"/>",
			"</tag>",
			"</meta>",
			"<name>",
			"<family value=\"FAMILY\"/>",
			"</name>",
			"</Patient>"));
		//@formatter:on

		Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, enc);
		List<UriType> gotLabels = parsed.getMeta().getProfile();
		assertEquals(2, gotLabels.size());
		UriType label = gotLabels.get(0);
		assertEquals("http://foo/Profile1", label.getValue());
		label = gotLabels.get(1);
		assertEquals("http://foo/Profile2", label.getValue());

		List<Coding> tagList = parsed.getMeta().getTag();
		assertEquals(2, tagList.size());
		assertEquals("scheme1", tagList.get(0).getSystem());
		assertEquals("term1", tagList.get(0).getCode());
		assertEquals("label1", tagList.get(0).getDisplay());
		assertEquals("scheme2", tagList.get(1).getSystem());
		assertEquals("term2", tagList.get(1).getCode());
		assertEquals("label2", tagList.get(1).getDisplay());

		tagList = parsed.getMeta().getSecurity();
		assertEquals(2, tagList.size());
		assertEquals("sec_scheme1", tagList.get(0).getSystem());
		assertEquals("sec_term1", tagList.get(0).getCode());
		assertEquals("sec_label1", tagList.get(0).getDisplay());
		assertEquals("sec_scheme2", tagList.get(1).getSystem());
		assertEquals("sec_term2", tagList.get(1).getCode());
		assertEquals("sec_label2", tagList.get(1).getDisplay());
	}

	@Test
	public void testEncodeAndParseMetaProfiles() {
		Patient p = new Patient();
		p.addName().addFamily("FAMILY");

		p.getMeta().addTag().setSystem("scheme1").setCode("term1").setDisplay("label1");
		p.getMeta().addTag().setSystem("scheme2").setCode("term2").setDisplay("label2");

		String enc = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
		ourLog.info(enc);

		//@formatter:off
		assertThat(enc, stringContainsInOrder("<Patient xmlns=\"http://hl7.org/fhir\">",
			"<meta>",
			"<tag>",
			"<system value=\"scheme1\"/>",
			"<code value=\"term1\"/>",
			"<display value=\"label1\"/>",
			"</tag>",
			"<tag>",
			"<system value=\"scheme2\"/>",
			"<code value=\"term2\"/>",
			"<display value=\"label2\"/>",
			"</tag>",
			"</meta>",
			"<name>",
			"<family value=\"FAMILY\"/>",
			"</name>",
			"</Patient>"));
		//@formatter:on

		Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, enc);
		assertThat(parsed.getMeta().getProfile(), empty());

		List<Coding> tagList = parsed.getMeta().getTag();
		assertEquals(2, tagList.size());
		assertEquals("scheme1", tagList.get(0).getSystem());
		assertEquals("term1", tagList.get(0).getCode());
		assertEquals("label1", tagList.get(0).getDisplay());
		assertEquals("scheme2", tagList.get(1).getSystem());
		assertEquals("term2", tagList.get(1).getCode());
		assertEquals("label2", tagList.get(1).getDisplay());
	}

	/**
	 * See #336
	 */
	@Test
	public void testEncodeAndParseNullPrimitiveWithExtensions() {

		Patient p = new Patient();
		p.setId("patid");
		HumanName name = p.addName();
		name.addGivenElement().setValue(null).setId("f0").addExtension(new Extension("http://foo", new StringType("FOOEXT0")));
		name.addGivenElement().setValue("V1").setId("f1").addExtension((Extension) new Extension("http://foo", new StringType("FOOEXT1")).setId("ext1id"));
		name.addGivenElement(); // this one shouldn't get encoded
		name.addGivenElement().setValue(null).addExtension(new Extension("http://foo", new StringType("FOOEXT3")));
		name.setId("nameid");

		String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
		ourLog.info(output);

		output = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(p);
		String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><id value=\"patid\"/><name id=\"nameid\"><given id=\"f0\"><extension url=\"http://foo\"><valueString value=\"FOOEXT0\"/></extension></given><given id=\"f1\" value=\"V1\"><extension id=\"ext1id\" url=\"http://foo\"><valueString value=\"FOOEXT1\"/></extension></given><given><extension url=\"http://foo\"><valueString value=\"FOOEXT3\"/></extension></given></name></Patient>";

		ourLog.info("Expected: {}", expected);
		ourLog.info("Actual  : {}", output);

		assertEquals(expected, output);

		p = ourCtx.newXmlParser().parseResource(Patient.class, output);
		assertEquals("patid", p.getIdElement().getIdPart());

		name = p.getName().get(0);
		assertEquals("nameid", name.getId());
		assertEquals(3, name.getGiven().size());

		assertEquals(null, name.getGiven().get(0).getValue());
		assertEquals("V1", name.getGiven().get(1).getValue());
		assertEquals(null, name.getGiven().get(2).getValue());

		assertEquals("f0", name.getGiven().get(0).getId());
		assertEquals("f1", name.getGiven().get(1).getId());
		assertEquals(null, name.getGiven().get(2).getId());

		assertEquals(1, name.getGiven().get(0).getExtension().size());
		assertEquals("http://foo", name.getGiven().get(0).getExtension().get(0).getUrl());
		assertEquals("FOOEXT0", ((StringType) name.getGiven().get(0).getExtension().get(0).getValue()).getValue());
		assertEquals(null, name.getGiven().get(0).getExtension().get(0).getId());

		assertEquals(1, name.getGiven().get(1).getExtension().size());
		assertEquals("http://foo", name.getGiven().get(1).getExtension().get(0).getUrl());
		assertEquals("FOOEXT1", ((StringType) name.getGiven().get(1).getExtension().get(0).getValue()).getValue());
		assertEquals("ext1id", name.getGiven().get(1).getExtension().get(0).getId());

		assertEquals(1, name.getGiven().get(2).getExtension().size());
		assertEquals("http://foo", name.getGiven().get(2).getExtension().get(0).getUrl());
		assertEquals("FOOEXT3", ((StringType) name.getGiven().get(2).getExtension().get(0).getValue()).getValue());
		assertEquals(null, name.getGiven().get(2).getExtension().get(0).getId());

	}




	@Test
	public void testEncodeAndParseSecurityLabels() {
		Patient p = new Patient();
		p.addName().addFamily("FAMILY");

		List<Coding> labels = new ArrayList<Coding>();
		labels.add(new Coding().setSystem("SYSTEM1").setCode("CODE1").setDisplay("DISPLAY1").setVersion("VERSION1"));
		labels.add(new Coding().setSystem("SYSTEM2").setCode("CODE2").setDisplay("DISPLAY2").setVersion("VERSION2"));
		p.getMeta().getSecurity().addAll(labels);

		String enc = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
		ourLog.info(enc);

		//@formatter:off
		assertThat(enc, stringContainsInOrder("<Patient xmlns=\"http://hl7.org/fhir\">",
			"<meta>",
			"<security>",
			"<system value=\"SYSTEM1\"/>",
			"<version value=\"VERSION1\"/>",
			"<code value=\"CODE1\"/>",
			"<display value=\"DISPLAY1\"/>",
			"</security>",
			"<security>",
			"<system value=\"SYSTEM2\"/>",
			"<version value=\"VERSION2\"/>",
			"<code value=\"CODE2\"/>",
			"<display value=\"DISPLAY2\"/>",
			"</security>",
			"</meta>",
			"<name>",
			"<family value=\"FAMILY\"/>",
			"</name>",
			"</Patient>"));
		//@formatter:on

		Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, enc);
		List<Coding> gotLabels = parsed.getMeta().getSecurity();

		assertEquals(2, gotLabels.size());

		Coding label = gotLabels.get(0);
		assertEquals("SYSTEM1", label.getSystem());
		assertEquals("CODE1", label.getCode());
		assertEquals("DISPLAY1", label.getDisplay());
		assertEquals("VERSION1", label.getVersion());

		label = gotLabels.get(1);
		assertEquals("SYSTEM2", label.getSystem());
		assertEquals("CODE2", label.getCode());
		assertEquals("DISPLAY2", label.getDisplay());
		assertEquals("VERSION2", label.getVersion());
	}


	@Test
	public void testEncodeBinaryWithNoContentType() {
		Binary b = new Binary();
		b.setContent(new byte[] { 1, 2, 3, 4 });

		String output = ourCtx.newXmlParser().encodeResourceToString(b);
		ourLog.info(output);

		assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"><content value=\"AQIDBA==\"/></Binary>", output);
	}

	@Test
	public void testEncodeBundleWithContained() {
		DiagnosticReport rpt = new DiagnosticReport();
		rpt.addResult().setResource(new Observation().setCode(new CodeableConcept().setText("Sharp1")).setId("#1"));
		rpt.addResult().setResource(new Observation().setCode(new CodeableConcept().setText("Uuid1")).setId("urn:uuid:UUID1"));

		Bundle b = new Bundle();
		b.addEntry().setResource(rpt);

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
		ourLog.info(encoded);

		assertThat(encoded, stringContainsInOrder("<DiagnosticReport", "<contained", "<Observation", "<text value=\"Sharp1\"", "</DiagnosticReport"));
		assertThat(encoded, not(stringContainsInOrder("<DiagnosticReport", "<contained", "<Observation", "<contained", "<Observation", "</DiagnosticReport")));
	}

	/**
	 * See #326
	 */
	@Test
	public void testEncodeContainedResource() {
		Patient patient = new Patient();
		patient.getBirthDateElement().setValueAsString("2016-04-05");
		patient.addExtension().setUrl("test").setValue(new Reference(new Condition()));

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
		ourLog.info(encoded);

		//@formatter:off
		assertThat(encoded, stringContainsInOrder(
			"<Patient xmlns=\"http://hl7.org/fhir\">",
			"<contained>",
			"<Condition xmlns=\"http://hl7.org/fhir\">",
			"<id value=\"1\"/>",
			"</Condition>",
			"</contained>",
			"<extension url=\"test\">",
			"<valueReference>",
			"<reference value=\"#1\"/>",
			"</valueReference>",
			"</extension>",
			"<birthDate value=\"2016-04-05\"/>",
			"</Patient>"
		));
		//@formatter:on
	}

	/**
	 * See #113
	 */
	@Test
	public void testEncodeContainedResources() {

		MedicationOrder medicationPrescript = new MedicationOrder();

		String medId = "123";
		CodeableConcept codeDt = new CodeableConcept().addCoding(new Coding().setSystem("urn:sys").setCode("code1"));

		// Adding medication to Contained.
		Medication medResource = new Medication();
		medResource.setCode(codeDt);
		medResource.setId("#" + String.valueOf(medId));
		medicationPrescript.getContained().add(medResource);

		// Medication reference. This should point to the contained resource.
		Reference medRefDt = new Reference("#" + medId);
		medRefDt.setDisplay("MedRef");
		medicationPrescript.setMedication(medRefDt);

		IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
		String encoded = p.encodeResourceToString(medicationPrescript);
		ourLog.info(encoded);

		// @formatter:on
		assertThat(encoded,
			stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"123\"/>", "<code>", "<coding>",
				"<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>", "</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#123\"/>",
				"<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
		//@formatter:off

	}

	/**
	 * See #113
	 */
	@Test
	public void testEncodeContainedResourcesAutomatic() {

		MedicationOrder medicationPrescript = new MedicationOrder();
		String nameDisp = "MedRef";
		CodeableConcept codeDt = new CodeableConcept().addCoding(new Coding("urn:sys", "code1", null));

		// Adding medication to Contained.
		Medication medResource = new Medication();
		// No ID set
		medResource.setCode(codeDt);

		// Medication reference. This should point to the contained resource.
		Reference medRefDt = new Reference();
		medRefDt.setDisplay(nameDisp);
		// Resource reference set, but no ID
		medRefDt.setResource(medResource);
		medicationPrescript.setMedication(medRefDt);

		IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
		String encoded = p.encodeResourceToString(medicationPrescript);
		ourLog.info(encoded);

		//@formatter:on
		assertThat(encoded,
			stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"1\"/>", "<code>", "<coding>",
				"<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>", "</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#1\"/>",
				"<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
		//@formatter:off
	}

	/**
	 * See #113
	 */
	@Test
	public void testEncodeContainedResourcesManualContainUsingNonLocalId() {

		MedicationOrder medicationPrescript = new MedicationOrder();

		String medId = "123";
		CodeableConcept codeDt = new CodeableConcept().addCoding(new Coding("urn:sys", "code1", null));

		// Adding medication to Contained.
		Medication medResource = new Medication();
		medResource.setCode(codeDt);
		medResource.setId(String.valueOf(medId)); // ID does not start with '#'
		medicationPrescript.getContained().add(medResource);

		// Medication reference. This should point to the contained resource.
		Reference medRefDt = new Reference("#" + medId);
		medRefDt.setDisplay("MedRef");
		medicationPrescript.setMedication(medRefDt);

		IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
		String encoded = p.encodeResourceToString(medicationPrescript);
		ourLog.info(encoded);

		//@formatter:on
		assertThat(encoded,
			stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"123\"/>", "<code>", "<coding>",
				"<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>", "</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#123\"/>",
				"<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
		//@formatter:off

	}

	@Test
	public void testEncodeContainedWithNarrativeIsSuppresed() throws Exception {
		IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);

		// Create an organization, note that the organization does not have an ID
		Organization org = new Organization();
		org.getNameElement().setValue("Contained Test Organization");
		org.getText().setDivAsString("<div>FOOBAR</div>");

		// Create a patient
		Patient patient = new Patient();
		patient.setId("Patient/1333");
		patient.addIdentifier().setSystem("urn:mrns").setValue("253345");
		patient.getText().setDivAsString("<div>BARFOO</div>");
		patient.getManagingOrganization().setResource(org);

		String encoded = parser.encodeResourceToString(patient);
		ourLog.info(encoded);

		assertThat(encoded, stringContainsInOrder("<Patient", "<text>", "<div xmlns=\"http://www.w3.org/1999/xhtml\">BARFOO</div>", "<contained>", "<Organization", "</Organization"));
		assertThat(encoded, not(stringContainsInOrder("<Patient", "<text>", "<contained>", "<Organization", "<text", "</Organization")));

		assertThat(encoded, not(containsString("FOOBAR")));
		assertThat(encoded, (containsString("BARFOO")));

	}

	/**
	 * Make sure whitespace is preserved for pre tags
	 */
	@Test
	public void testEncodeDivWithPreNonPrettyPrint() {

		Patient p = new Patient();
		p.getText().setDivAsString("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3  <b>BOLD</b></pre></p></div>");

		String output = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(p);
		ourLog.info(output);

		//@formatter:off
		assertThat(output, stringContainsInOrder(
			"<text><div",
			"<p>A P TAG</p><p>",
			"<pre>line1\nline2\nline3  <b>BOLD</b></pre>"
		));
		//@formatter:on

	}

	@Test
	public void testEncodeDivWithPrePrettyPrint() {

		Patient p = new Patient();
		p.getText().setDivAsString("<div>\n\n<p>A P TAG</p><p><pre>line1\nline2\nline3  <b>BOLD</b></pre></p></div>");

		String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
		ourLog.info(output);

		//@formatter:off
		assertThat(output, stringContainsInOrder(
			"   <text>",
			"      <div",
			"         <pre>line1\nline2\nline3  <b>BOLD</b></pre>"
		));
		//@formatter:on

	}

	@Test
	public void testEncodeDoesntIncludeUuidId() {
		Patient p = new Patient();
		p.setId(new IdType("urn:uuid:42795ed8-041f-4ebf-b6f4-78ef6f64c2f2"));
		p.addIdentifier().setSystem("ACME");

		String actual = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
		assertThat(actual, not(containsString("78ef6f64c2f2")));
	}

	@Test
	public void testEncodeEmptyBinary() {
		String output = ourCtx.newXmlParser().encodeResourceToString(new Binary());
		assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"/>", output);
	}

	/**
	 * #158
	 */
	@Test
	public void testEncodeEmptyTag() {
		ArrayList<Coding> tagList = new ArrayList<Coding>();
		tagList.add(new Coding());
		tagList.add(new Coding().setDisplay("Label"));

		Patient p = new Patient();
		p.getMeta().getTag().addAll(tagList);

		String encoded = ourCtx.newXmlParser().encodeResourceToString(p);
		assertThat(encoded, not(containsString("tag")));
	}

	/**
	 * #158
	 */
	@Test
	public void testEncodeEmptyTag2() {
		ArrayList<Coding> tagList = new ArrayList<Coding>();
		tagList.add(new Coding().setSystem("scheme").setCode("code"));
		tagList.add(new Coding().setDisplay("Label"));

		Patient p = new Patient();
		p.getMeta().getTag().addAll(tagList);

		String encoded = ourCtx.newXmlParser().encodeResourceToString(p);
		assertThat(encoded, containsString("tag"));
		assertThat(encoded, containsString("scheme"));
		assertThat(encoded, not(containsString("Label")));
	}

	@Test
	public void testEncodeExtensionUndeclaredNonModifier() {
		Observation obs = new Observation();
		obs.setId("1");
		obs.getMeta().addProfile("http://profile");
		Extension ext = obs.addExtension();
		ext.setUrl("http://exturl").setValue(new StringType("ext_url_value"));

		obs.getCode().setText("CODE");

		IParser parser = ourCtx.newXmlParser();

		String output = parser.setPrettyPrint(true).encodeResourceToString(obs);
		ourLog.info(output);

		//@formatter:off
		assertThat(output, stringContainsInOrder(
			"<id value=\"1\"/>",
			"<meta>",
			"<profile value=\"http://profile\"/>",
			"<extension url=\"http://exturl\">",
			"<valueString value=\"ext_url_value\"/>",
			"<text value=\"CODE\"/>"
		));
		assertThat(output, not(stringContainsInOrder(
			"<url value=\"http://exturl\"/>"
		)));
		//@formatter:on

		obs = parser.parseResource(Observation.class, output);
		assertEquals(1, obs.getExtension().size());
		assertEquals("http://exturl", obs.getExtension().get(0).getUrl());
		assertEquals("ext_url_value", ((StringType) obs.getExtension().get(0).getValue()).getValue());
	}

	@Test
	public void testEncodeExtensionUndeclaredNonModifierWithChildExtension() {
		Observation obs = new Observation();
		obs.setId("1");
		obs.getMeta().addProfile("http://profile");
		Extension ext = obs.addExtension();
		ext.setUrl("http://exturl");

		Extension subExt = ext.addExtension();
		subExt.setUrl("http://subext").setValue(new StringType("sub_ext_value"));

		obs.getCode().setText("CODE");

		IParser parser = ourCtx.newXmlParser();

		String output = parser.setPrettyPrint(true).encodeResourceToString(obs);
		ourLog.info(output);

		//@formatter:off
		assertThat(output, stringContainsInOrder(
			"<id value=\"1\"/>",
			"<meta>",
			"<profile value=\"http://profile\"/>",
			"<extension url=\"http://exturl\">",
			"<extension url=\"http://subext\">",
			"<valueString value=\"sub_ext_value\"/>",
			"<text value=\"CODE\"/>"
		));
		assertThat(output, not(stringContainsInOrder(
			"<url value=\"http://exturl\"/>"
		)));
		//@formatter:on

		obs = parser.parseResource(Observation.class, output);
		assertEquals(1, obs.getExtension().size());
		assertEquals("http://exturl", obs.getExtension().get(0).getUrl());
		assertEquals(1, obs.getExtension().get(0).getExtension().size());
		assertEquals("http://subext", obs.getExtension().get(0).getExtension().get(0).getUrl());
		assertEquals("sub_ext_value", ((StringType) obs.getExtension().get(0).getExtension().get(0).getValue()).getValue());
	}

	/**
	 * See #327
	 */
	@Test
	public void testEncodeExtensionWithContainedResource() {

		TestPatientFor327 patient = new TestPatientFor327();
		patient.setBirthDateElement(new DateType("2016-04-14"));

		List<Reference> conditions = new ArrayList<Reference>();
		Condition condition = new Condition();
		condition.addBodySite().setText("BODY SITE");
		conditions.add(new Reference(condition));
		patient.setCondition(conditions);

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
		ourLog.info(encoded);

		//@formatter:off
		assertThat(encoded, stringContainsInOrder(
			"<Patient xmlns=\"http://hl7.org/fhir\">",
			"<contained>",
			"<Condition xmlns=\"http://hl7.org/fhir\">",
			"<id value=\"1\"/>",
			"<bodySite>",
			"<text value=\"BODY SITE\"/>",
			"</bodySite>",
			"</Condition>",
			"</contained>",
			"<extension url=\"testCondition\">",
			"<valueReference>",
			"<reference value=\"#1\"/>",
			"</valueReference>",
			"</extension>",
			"<birthDate value=\"2016-04-14\"/>",
			"</Patient>"
		));
		//@formatter:on
	}

	@Test
	public void testEncodeExtensionWithResourceContent() {
		IParser parser = ourCtx.newXmlParser();

		Patient patient = new Patient();
		patient.addAddress().setUse(Address.AddressUse.HOME);
		patient.addExtension(new Extension("urn:foo", new Reference("Organization/123")));

		String val = parser.encodeResourceToString(patient);
		ourLog.info(val);
		assertThat(val, StringContains.containsString("<extension url=\"urn:foo\"><valueReference><reference value=\"Organization/123\"/></valueReference></extension>"));

		Patient actual = parser.parseResource(Patient.class, val);
		assertEquals(Address.AddressUse.HOME, patient.getAddress().get(0).getUse());
		List<Extension> ext = actual.getExtension();
		assertEquals(1, ext.size());
		Reference ref = (Reference) ext.get(0).getValue();
		assertEquals("Organization/123", ref.getReference());

	}

	@Test
	public void testEncodeHistoryEncodeVersionsAtPath3() {
		ourCtx = FhirContext.forDstu2_1();

		assertNull(ourCtx.newXmlParser().getStripVersionsFromReferences());

		AuditEvent auditEvent = new AuditEvent();
		auditEvent.addEntity().setReference(new Reference("http://foo.com/Organization/2/_history/1"));

		IParser parser = ourCtx.newXmlParser();

		parser.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference");
		String enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
		ourLog.info(enc);
		assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2/_history/1\"/>"));

		parser.setDontStripVersionsFromReferencesAtPaths(new ArrayList<String>());
		enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
		ourLog.info(enc);
		assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2\"/>"));

		parser.setDontStripVersionsFromReferencesAtPaths((String[]) null);
		enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
		ourLog.info(enc);
		assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2\"/>"));

		parser.setDontStripVersionsFromReferencesAtPaths((List<String>) null);
		enc = parser.setPrettyPrint(true).encodeResourceToString(auditEvent);
		ourLog.info(enc);
		assertThat(enc, containsString("<reference value=\"http://foo.com/Organization/2\"/>"));

	}

	@Test
	public void testEncodeNarrativeSuppressed() {
		Patient patient = new Patient();
		patient.setId("Patient/1/_history/1");
		patient.getText().setDivAsString("<div>THE DIV</div>");
		patient.addName().addFamily("FAMILY");
		patient.setMaritalStatus(new CodeableConcept().addCoding(new Coding().setCode("D")));
		patient.setMaritalStatus(new CodeableConcept().addCoding(new Coding().setCode("D")));

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).setSuppressNarratives(true).encodeResourceToString(patient);
		ourLog.info(encoded);

		assertThat(encoded, containsString("<Patient"));
		assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
		assertThat(encoded, not(containsString("text")));
		assertThat(encoded, not(containsString("THE DIV")));
		assertThat(encoded, containsString("family"));
		assertThat(encoded, containsString("maritalStatus"));
	}

	@Test
	public void testEncodeNonContained() {
		// Create an organization
		Organization org = new Organization();
		org.setId("Organization/65546");
		org.getNameElement().setValue("Contained Test Organization");

		// Create a patient
		Patient patient = new Patient();
		patient.setId("Patient/1333");
		patient.addIdentifier().setSystem("urn:mrns").setValue("253345");
		patient.getManagingOrganization().setResource(org);

		// Create a list containing both resources. In a server method, you might just
		// return this list, but here we will create a bundle to encode.
		List<IBaseResource> resources = new ArrayList<IBaseResource>();
		resources.add(org);
		resources.add(patient);

		// Create a bundle with both
		Bundle b = new Bundle();
		b.addEntry().setResource(org);
		b.addEntry().setResource(patient);

		// Encode the buntdle
		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
		ourLog.info(encoded);
		assertThat(encoded, not(containsString("<contained>")));
		assertThat(encoded, stringContainsInOrder("<Organization", "<id value=\"65546\"/>", "</Organization>"));
		assertThat(encoded, containsString("<reference value=\"Organization/65546\"/>"));
		assertThat(encoded, stringContainsInOrder("<Patient", "<id value=\"1333\"/>", "</Patient>"));

		encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
		ourLog.info(encoded);
		assertThat(encoded, not(containsString("<contained>")));
		assertThat(encoded, containsString("<reference value=\"Organization/65546\"/>"));

	}





	@Test
	public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {

		Patient patient = new Patient();
		patient.setId("phitcc_pat_normal");
		patient.addName().addGiven("Patty").setUse(HumanName.NameUse.NICKNAME);
		patient.addTelecom().setSystem(ContactPoint.ContactPointSystem.EMAIL).setValue("patpain@ehealthinnovation.org");
		patient.setGender(Enumerations.AdministrativeGender.FEMALE);
		patient.setBirthDateElement(new DateType("2001-10-13"));

		DateTimeType obsEffectiveTime = new DateTimeType("2015-04-11T12:22:01-04:00");

		Observation obsParent = new Observation();
		obsParent.setId("phitcc_obs_bp_parent");
		obsParent.getSubject().setResource(patient);
		obsParent.setStatus(Observation.ObservationStatus.FINAL);
		obsParent.setEffective(obsEffectiveTime);

		Observation obsSystolic = new Observation();
		obsSystolic.setId("phitcc_obs_bp_dia");
		obsSystolic.getSubject().setResource(patient);
		obsSystolic.setEffective(obsEffectiveTime);
		obsParent.addRelated().setType(Observation.ObservationRelationshipType.HASMEMBER).setTarget(new Reference(obsSystolic));

		Observation obsDiastolic = new Observation();
		obsDiastolic.setId("phitcc_obs_bp_dia");
		obsDiastolic.getSubject().setResource(patient);
		obsDiastolic.setEffective(obsEffectiveTime);
		obsParent.addRelated().setType(Observation.ObservationRelationshipType.HASMEMBER).setTarget(new Reference(obsDiastolic));

		String str = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(obsParent);
		ourLog.info(str);

		assertThat(str, containsString("<reference value=\"Patient/phitcc_pat_normal\"/>"));
		assertThat(str, containsString("<reference value=\"Observation/phitcc_obs_bp_dia\"/>"));
	}


	@Test
	public void testEncodeSummary() {
		Patient patient = new Patient();
		patient.setId("Patient/1/_history/1");
		patient.getText().setDivAsString("<div>THE DIV</div>");
		patient.addName().addFamily("FAMILY");
		patient.setMaritalStatus(new CodeableConcept().addCoding(new Coding().setCode("D")));

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).setSummaryMode(true).encodeResourceToString(patient);
		ourLog.info(encoded);

		assertThat(encoded, containsString("<Patient"));
		assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
		assertThat(encoded, not(containsString("THE DIV")));
		assertThat(encoded, containsString("family"));
		assertThat(encoded, not(containsString("maritalStatus")));
	}

	@Test
	public void testEncodeSummary2() {
		Patient patient = new Patient();
		patient.setId("Patient/1/_history/1");
		patient.getText().setDivAsString("<div>THE DIV</div>");
		patient.addName().addFamily("FAMILY");
		patient.setMaritalStatus(new CodeableConcept().addCoding(new Coding().setCode("D")));

		patient.getMeta().addTag().setSystem("foo").setCode("bar");

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).setSummaryMode(true).encodeResourceToString(patient);
		ourLog.info(encoded);

		assertThat(encoded, containsString("<Patient"));
		assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"foo\"/>", "<code value=\"bar\"/>", "</tag>"));
		assertThat(encoded, stringContainsInOrder("<tag>", "<system value=\"" + Constants.TAG_SUBSETTED_SYSTEM_DSTU3 + "\"/>", "<code value=\"" + Constants.TAG_SUBSETTED_CODE + "\"/>", "</tag>"));
		assertThat(encoded, not(containsString("THE DIV")));
		assertThat(encoded, containsString("family"));
		assertThat(encoded, not(containsString("maritalStatus")));
	}

	@Test
	public void testEncodeWithContained() {
		List<Resource> contained = new ArrayList<Resource>();

		// Will be added by reference
		Patient p = new Patient();
		p.setId("#" + "1000");
		contained.add(p);

		// Will be added by direct resource object
		Location l = new Location();
		l.setId("#" + "1001");
		contained.add(l);

		// Will not be referred to (and therefore shouldn't appear in output)
		Location l2 = new Location();
		l2.setId("#1002");
		contained.add(l2);

		Appointment appointment = new Appointment();
		appointment.setId("1234");
		appointment.getContained().addAll(contained);

		appointment.addParticipant().getActor().setReference("#1000");
		appointment.addParticipant().getActor().setResource(l);

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(appointment);
		ourLog.info(encoded);

		//@formatter:off
		assertThat(encoded, stringContainsInOrder(
			"<Appointment xmlns=\"http://hl7.org/fhir\">",
			"<id value=\"1234\"/>",
			"<contained>",
			"<Patient xmlns=\"http://hl7.org/fhir\">",
			"<id value=\"1000\"/>",
			"</Patient>",
			"</contained>",
			"<contained>",
			"<Location xmlns=\"http://hl7.org/fhir\">",
			"<id value=\"1001\"/>",
			"</Location>",
			"</contained>",
			"<participant>",
			"<actor>",
			"<reference value=\"#1000\"/>",
			"</actor>",
			"</participant>",
			"<participant>",
			"<actor>",
			"<reference value=\"#1001\"/>",
			"</actor>",
			"</participant>",
			"</Appointment>"
		));
		//@formatter:on

		assertThat(encoded, not(containsString("#1002")));
	}

	@Test
	public void testEncodeWithDontEncodeElements() throws Exception {
		Patient patient = new Patient();
		patient.setId("123");
		patient.getMeta().addProfile("http://profile");
		patient.addName().addFamily("FAMILY").addGiven("GIVEN");
		patient.addAddress().addLine("LINE1");

		{
			IParser p = ourCtx.newXmlParser();
			p.setDontEncodeElements(Sets.newHashSet("*.meta", "*.id"));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(patient);
			ourLog.info(out);
			assertThat(out, containsString("Patient"));
			assertThat(out, containsString("name"));
			assertThat(out, containsString("address"));
			assertThat(out, not(containsString("id")));
			assertThat(out, not(containsString("meta")));
		}
		{
			IParser p = ourCtx.newXmlParser();
			p.setDontEncodeElements(Sets.newHashSet("Patient.meta", "Patient.id"));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(patient);
			ourLog.info(out);
			assertThat(out, containsString("Patient"));
			assertThat(out, containsString("name"));
			assertThat(out, containsString("address"));
			assertThat(out, not(containsString("id")));
			assertThat(out, not(containsString("meta")));
		}
		{
			IParser p = ourCtx.newXmlParser();
			p.setDontEncodeElements(Sets.newHashSet("Patient.name.family"));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(patient);
			ourLog.info(out);
			assertThat(out, containsString("GIVEN"));
			assertThat(out, not(containsString("FAMILY")));
		}
		{
			IParser p = ourCtx.newXmlParser();
			p.setDontEncodeElements(Sets.newHashSet("*.meta", "*.id"));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(patient);
			ourLog.info(out);
			assertThat(out, containsString("Patient"));
			assertThat(out, containsString("name"));
			assertThat(out, containsString("address"));
			assertThat(out, not(containsString("id")));
			assertThat(out, not(containsString("meta")));
		}
		{
			IParser p = ourCtx.newXmlParser();
			p.setDontEncodeElements(Sets.newHashSet("Patient.meta"));
			p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(patient);
			ourLog.info(out);
			assertThat(out, containsString("Patient"));
			assertThat(out, containsString("name"));
			assertThat(out, containsString("id"));
			assertThat(out, not(containsString("address")));
		}
	}

	@Test
	public void testEncodeWithEncodeElements() throws Exception {
		Patient patient = new Patient();
		patient.getMeta().addProfile("http://profile");
		patient.addName().addFamily("FAMILY");
		patient.addAddress().addLine("LINE1");

		Bundle bundle = new Bundle();
		bundle.setTotal(100);
		bundle.addEntry().setResource(patient);

		{
			IParser p = ourCtx.newXmlParser();
			p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name", "Bundle.entry")));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(bundle);
			ourLog.info(out);
			assertThat(out, not(containsString("total")));
			assertThat(out, (containsString("Patient")));
			assertThat(out, (containsString("name")));
			assertThat(out, not(containsString("address")));
		}
		{
			IParser p = ourCtx.newXmlParser();
			p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(bundle);
			ourLog.info(out);
			assertThat(out, (containsString("total")));
			assertThat(out, (containsString("Patient")));
			assertThat(out, (containsString("name")));
			assertThat(out, not(containsString("address")));
		}
		{
			IParser p = ourCtx.newXmlParser();
			p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
			p.setPrettyPrint(true);
			String out = p.encodeResourceToString(bundle);
			ourLog.info(out);
			assertThat(out, (containsString("total")));
			assertThat(out, (containsString("Patient")));
			assertThat(out, (containsString("name")));
			assertThat(out, (containsString("address")));
		}

	}

	@Test
	public void testMoreExtensions() throws Exception {

		Patient patient = new Patient();
		patient.addIdentifier().setUse(Identifier.IdentifierUse.OFFICIAL).setSystem("urn:example").setValue("7000135");

		Extension ext = new Extension();
		ext.setUrl("http://example.com/extensions#someext");
		ext.setValue(new DateTimeType("2011-01-02T11:13:15"));

		// Add the extension to the resource
		patient.addExtension(ext);
		// END SNIPPET: resourceExtension

		// START SNIPPET: resourceStringExtension
		HumanName name = patient.addName();
		name.addFamily("Shmoe");
		StringType given = name.addGivenElement();
		given.setValue("Joe");
		Extension ext2 = new Extension().setUrl("http://examples.com#givenext").setValue(new StringType("given"));
		given.addExtension(ext2);

		StringType given2 = name.addGivenElement();
		given2.setValue("Shmoe");
		Extension given2ext = new Extension().setUrl("http://examples.com#givenext_parent");
		given2.addExtension(given2ext);
		Extension givenExtChild = new Extension();
		givenExtChild.setUrl("http://examples.com#givenext_child").setValue(new StringType("CHILD"));
		given2ext.addExtension(givenExtChild);
		// END SNIPPET: resourceStringExtension

		// START SNIPPET: subExtension
		Extension parent = new Extension().setUrl("http://example.com#parent");
		patient.addExtension(parent);

		Extension child1 = new Extension().setUrl("http://example.com#child").setValue(new StringType("value1"));
		parent.addExtension(child1);

		Extension child2 = new Extension().setUrl("http://example.com#child").setValue(new StringType("value1"));
		parent.addExtension(child2);
		// END SNIPPET: subExtension

		String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
		ourLog.info(output);

		String enc = ourCtx.newXmlParser().encodeResourceToString(patient);
		assertThat(enc, containsString("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://example.com/extensions#someext\"><valueDateTime value=\"2011-01-02T11:13:15\"/></extension>"));
		assertThat(enc, containsString(
			"<extension url=\"http://example.com#parent\"><extension url=\"http://example.com#child\"><valueString value=\"value1\"/></extension><extension url=\"http://example.com#child\"><valueString value=\"value1\"/></extension></extension>"));
		assertThat(enc, containsString("<given value=\"Joe\"><extension url=\"http://examples.com#givenext\"><valueString value=\"given\"/></extension></given>"));
		assertThat(enc, containsString(
			"<given value=\"Shmoe\"><extension url=\"http://examples.com#givenext_parent\"><extension url=\"http://examples.com#givenext_child\"><valueString value=\"CHILD\"/></extension></extension></given>"));
	}

	@Test
	public void testOmitResourceId() {
		Patient p = new Patient();
		p.setId("123");
		p.addName().addFamily("ABC");

		assertThat(ourCtx.newXmlParser().encodeResourceToString(p), stringContainsInOrder("123", "ABC"));
		assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), containsString("ABC"));
		assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
	}


	@Test
	public void testParseAndEncodeComments() throws IOException {
		//@formatter:off
		String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"  <!--pre resource comment-->" +
			"  <id value=\"pat1\"/>\n" +
			"  <text>\n" +
			"    <status value=\"generated\"/>\n" +
			"    <div xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
			"\n" +
			"      <p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p>\n" +
			"\n" +
			"    </div>\n" +
			"  </text>\n" +
			"  <!--identifier comment 1-->\n" +
			"  <!--identifier comment 2-->\n" +
			"  <identifier>\n" +
			"    <!--use comment 1-->\n" +
			"    <!--use comment 2-->\n" +
			"    <use value=\"usual\"/>\n" +
			"    <type>\n" +
			"      <coding>\n" +
			"        <system value=\"http://hl7.org/fhir/v2/0203\"/>\n" +
			"        <code value=\"MR\"/>\n" +
			"      </coding>\n" +
			"    </type>\n" +
			"    <system value=\"urn:oid:0.1.2.3.4.5.6.7\"/>\n" +
			"    <value value=\"654321\"/>\n" +
			"  </identifier>\n" +
			"  <active value=\"true\"/>" +
			"  <!--post resource comment-->" +
			"</Patient>";
		//@formatter:off

		Patient res = ourCtx.newXmlParser().parseResource(Patient.class, input);
		res.getFormatCommentsPre();
		assertEquals("Patient/pat1", res.getId());
		assertEquals("654321", res.getIdentifier().get(0).getValue());
		assertEquals(true, res.getActive());

		assertThat(res.getIdElement().getFormatCommentsPre(), contains("pre resource comment"));
		assertThat(res.getIdentifier().get(0).getFormatCommentsPre(), contains("identifier comment 1", "identifier comment 2"));
		assertThat(res.getIdentifier().get(0).getUseElement().getFormatCommentsPre(), contains("use comment 1", "use comment 2"));
		assertThat(res.getActiveElement().getFormatCommentsPost(), contains("post resource comment"));

		String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res);
		ourLog.info(encoded);

		//@formatter:off
		assertThat(encoded, stringContainsInOrder(
			"\"identifier\": [",
			"{",
			"\"fhir_comments\":",
			"[",
			"\"identifier comment 1\"",
			",",
			"\"identifier comment 2\"",
			"]",
			"\"use\": \"usual\",",
			"\"_use\": {",
			"\"fhir_comments\":",
			"[",
			"\"use comment 1\"",
			",",
			"\"use comment 2\"",
			"]",
			"},",
			"\"type\""
		));
		//@formatter:off

		encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
		ourLog.info(encoded);

		//@formatter:off
		assertThat(encoded, stringContainsInOrder(
			"<Patient xmlns=\"http://hl7.org/fhir\">",
			"<id value=\"pat1\"/>",
			"<text>",
			"<status value=\"generated\"/>",
			"<div xmlns=\"http://www.w3.org/1999/xhtml\"> ",
			"<p>Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321</p> ",
			"</div>",
			"</text>",
			" <!--identifier comment 1-->\n",
			" <!--identifier comment 2-->",
			"<identifier>",
			"<!--use comment 1-->",
			"<!--use comment 2-->",
			"<use value=\"usual\"/>",
			"<type>",
			"<coding>",
			"<system value=\"http://hl7.org/fhir/v2/0203\"/>",
			"<code value=\"MR\"/>",
			"</coding>",
			"</type>",
			"<system value=\"urn:oid:0.1.2.3.4.5.6.7\"/>",
			"<value value=\"654321\"/>",
			"</identifier>",
			"<active value=\"true\"/>",
			"</Patient>"
		));
		//@formatter:off

	}

	@Test
	public void testParseAndEncodeCommentsOnExtensions() {
		//@formatter:off
		String input =
			"<Patient xmlns=\"http://hl7.org/fhir\">\n" +
				"  <!-- comment 1 -->\n" +
				"  <id value=\"someid\"/>\n" +
				"  <!-- comment 2 -->\n" +
				"  <extension url=\"urn:patientext:att\">\n" +
				"    <!-- comment 3 -->\n" +
				"    <valueAttachment>\n" +
				"      <!-- comment 4 -->\n" +
				"      <contentType value=\"aaaa\"/>\n" +
				"      <data value=\"AAAA\"/>\n" +
				"      <!-- comment 5 -->\n" +
				"    </valueAttachment>\n" +
				"    <!-- comment 6 -->\n" +
				"  </extension>\n" +
				"  <!-- comment 7 -->\n" +
				"</Patient>";

		Patient pat = ourCtx.newXmlParser().parseResource(Patient.class, input);
		String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(pat);
		ourLog.info(output);

		assertThat(output, stringContainsInOrder(
			"<Patient xmlns=\"http://hl7.org/fhir\">",
			"  <!-- comment 1 -->",
			"  <id value=\"someid\"/>",
			"  <!-- comment 2 -->",
			"  <extension url=\"urn:patientext:att\">",
			"    <!-- comment 3 -->",
			"    <valueAttachment>",
			"      <!-- comment 4 -->",
			"      <contentType value=\"aaaa\"/>",
			"      <data value=\"AAAA\"/>",
			"      <!-- comment 5 -->",
			"    </valueAttachment>",
			"    <!-- comment 6 -->",
			"  </extension>",
			"  <!-- comment 7 -->",
			"</Patient>"
		));

		output = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(pat);
		ourLog.info(output);

		assertThat(output, stringContainsInOrder(
			"{",
			"  \"resourceType\": \"Patient\",",
			"  \"id\": \"someid\",",
			"  \"_id\": {",
			"    \"fhir_comments\": [",
			"      \" comment 1 \"",
			"    ]",
			"  },",
			"  \"extension\": [",
			"    {",
			"      \"fhir_comments\": [",
			"        \" comment 2 \",",
			"        \" comment 7 \"",
			"      ],",
			"      \"url\": \"urn:patientext:att\",",
			"      \"valueAttachment\": {",
			"        \"fhir_comments\": [",
			"          \" comment 3 \",",
			"          \" comment 6 \"",
			"        ],",
			"        \"contentType\": \"aaaa\",",
			"        \"_contentType\": {",
			"          \"fhir_comments\": [",
			"            \" comment 4 \"",
			"          ]",
			"        },",
			"        \"data\": \"AAAA\",",
			"        \"_data\": {",
			"          \"fhir_comments\": [",
			"            \" comment 5 \"",
			"          ]",
			"        }",
			"      }",
			"    }",
			"  ]",
			"}"
		));

		//@formatter:on
	}


	@Test
	public void testParseAndEncodeNestedExtensions() {
		//@formatter:off
		String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"   <birthDate value=\"2005-03-04\">\n" +
			"      <extension url=\"http://my.fancy.extension.url\">\n" +
			"         <extension url=\"http://my.fancy.extension.url\">\n" +
			"            <valueString value=\"myNestedValue\"/>\n" +
			"         </extension>\n" +
			"      </extension>\n" +
			"   </birthDate>\n" +
			"</Patient>";
		//@formatter:on

		Patient p = ourCtx.newXmlParser().parseResource(Patient.class, input);
		DateType bd = p.getBirthDateElement();
		assertEquals("2005-03-04", bd.getValueAsString());

		List<Extension> exts = bd.getExtensionsByUrl("http://my.fancy.extension.url");
		assertEquals(1, exts.size());
		Extension ext = exts.get(0);
		assertEquals(null, ext.getValue());

		exts = ext.getExtensionsByUrl("http://my.fancy.extension.url");
		assertEquals(1, exts.size());
		ext = exts.get(0);
		assertEquals("myNestedValue", ((StringType) ext.getValue()).getValue());

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
		ourLog.info(encoded);

		//@formatter:off
		assertThat(encoded, stringContainsInOrder(
			"<Patient xmlns=\"http://hl7.org/fhir\">",
			"<birthDate value=\"2005-03-04\">",
			"<extension url=\"http://my.fancy.extension.url\">",
			"<extension url=\"http://my.fancy.extension.url\">",
			"<valueString value=\"myNestedValue\"/>",
			"</extension>",
			"</extension>",
			"</birthDate>",
			"</Patient>"));
		//@formatter:on

	}

	@Test
	public void testParseBundleNewWithPlaceholderIds() {
		//@formatter:off
		String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"    <id value=\"ringholm1430996763590912\"/>\n" +
			"    <entry>\n" +
			"        <fullUrl value=\"urn:oid:0.1.2.3\"/>\n" +
			"        <resource>\n" +
			"            <Provenance>\n" +
			"                <id value=\"0.1.2.3\"/>\n" +
			"            </Provenance>\n" +
			"        </resource>\n" +
			"    </entry>\n" +
			"</Bundle>\n";
		//@formatter:on

		Bundle parsed = ourCtx.newXmlParser().parseResource(Bundle.class, input);
		assertEquals("urn:oid:0.1.2.3", parsed.getEntry().get(0).getResource().getIdElement().getValue());

	}

	@Test
	public void testParseBundleNewWithPlaceholderIdsInBase1() {
		//@formatter:off
		String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"    <id value=\"ringholm1430996763590912\"/>\n" +
			"    <entry>\n" +
			"        <fullUrl value=\"urn:oid:0.1.2.3\"/>\n" +
			"        <resource>\n" +
			"            <Provenance>\n" +
			"                <id value=\"0.1.2.3\"/>\n" +
			"            </Provenance>\n" +
			"        </resource>\n" +
			"    </entry>\n" +
			"</Bundle>\n";
		//@formatter:on

		Bundle parsed = ourCtx.newXmlParser().parseResource(Bundle.class, input);
		assertEquals("urn:oid:0.1.2.3", parsed.getEntry().get(0).getResource().getIdElement().getValue());
	}

	@Test
	public void testParseBundleNewWithPlaceholderIdsInBase2() {
		//@formatter:off
		String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"    <id value=\"ringholm1430996763590912\"/>\n" +
			"    <entry>\n" +
			"        <fullUrl value=\"urn:uuid:0.1.2.3\"/>\n" +
			"        <resource>\n" +
			"            <Provenance>\n" +
			"                <id value=\"0.1.2.3\"/>\n" +
			"            </Provenance>\n" +
			"        </resource>\n" +
			"    </entry>\n" +
			"</Bundle>\n";
		//@formatter:on

		Bundle parsed = ourCtx.newXmlParser().parseResource(Bundle.class, input);
		assertEquals("urn:uuid:0.1.2.3", parsed.getEntry().get(0).getResource().getIdElement().getValue());

		//@formatter:off
		input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"    <id value=\"ringholm1430996763590912\"/>\n" +
			"    <entry>\n" +
			"        <fullUrl value=\"urn:uuid:0.1.2.3\"/>\n" +
			"        <resource>\n" +
			"            <Provenance>\n" +
			"                <id value=\"0.1.2.3\"/>\n" +
			"            </Provenance>\n" +
			"        </resource>\n" +
			"    </entry>\n" +
			"</Bundle>\n";
		//@formatter:on

		parsed = ourCtx.newXmlParser().parseResource(Bundle.class, input);
		assertEquals("urn:uuid:0.1.2.3", parsed.getEntry().get(0).getResource().getIdElement().getValue());

	}

	@Test
	public void testParseBundleOldStyleWithUnknownLinks() throws Exception {
		//@formatter:off
		String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"   <base value=\"http://foo/fhirBase1\"/>\n" +
			"   <total value=\"1\"/>\n" +
			"   <link>\n" +
			"      <relation value=\"foo\"/>\n" +
			"      <url value=\"http://localhost:52788/Binary?_pretty=true\"/>\n" +
			"   </link>\n" +
			"   <entry>\n" +
			"   <link>\n" +
			"      <relation value=\"bar\"/>\n" +
			"      <url value=\"http://localhost:52788/Binary?_pretty=true\"/>\n" +
			"   </link>\n" +
			"      <resource>\n" +
			"         <Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"            <id value=\"1\"/>\n" +
			"            <meta>\n" +
			"               <versionId value=\"2\"/>\n" +
			"               <lastUpdated value=\"2001-02-22T11:22:33-05:00\"/>\n" +
			"            </meta>\n" +
			"            <birthDate value=\"2012-01-02\"/>\n" +
			"         </Patient>\n" +
			"      </resource>\n" +
			"   </entry>\n" +
			"</Bundle>";
		//@formatter:on

		Bundle b = (Bundle) ourCtx.newXmlParser().parseResource(bundle);
		assertEquals(1, b.getEntry().size());

	}

	@Test
	public void testParseBundleOldWithPlaceholderIds() {
		//@formatter:off
		String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"    <id value=\"ringholm1430996763590912\"/>\n" +
			"    <entry>\n" +
			"        <fullUrl value=\"urn:oid:0.1.2.3\"/>\n" +
			"        <resource>\n" +
			"            <Provenance>\n" +
			"                <id value=\"0.1.2.3\"/>\n" +
			"            </Provenance>\n" +
			"        </resource>\n" +
			"    </entry>\n" +
			"</Bundle>\n";
		//@formatter:on

		Bundle parsed = (Bundle) ourCtx.newXmlParser().parseResource(input);
		assertEquals("urn:oid:0.1.2.3", parsed.getEntry().get(0).getResource().getId());

	}

	@Test
	public void testParseBundleWithBinary() {
		// TODO: implement this test, make sure we handle ID and meta correctly in Binary
	}



	@Test
	public void testParseBundleWithResourceId() {
		//@formatter:off
		String input = "<Bundle xmlns=\"http://hl7.org/fhir\">"
			+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"3\"/><lastUpdated value=\"2015-09-11T23:35:43.273-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
			+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"2\"/><lastUpdated value=\"2015-09-11T23:35:42.849-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
			+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"1\"/><lastUpdated value=\"2015-09-11T23:35:42.295-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
			+ "</Bundle>\n";
		//@formatter:on

		Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, input);
		assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/3", bundle.getEntry().get(0).getResource().getIdElement().getValue());
		assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/2", bundle.getEntry().get(1).getResource().getIdElement().getValue());
		assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/1", bundle.getEntry().get(2).getResource().getIdElement().getValue());
	}

	/**
	 * Thanks to Alexander Kley!
	 */
	@Test
	public void testParseContainedBinaryResource() {
		byte[] bin = new byte[] { 0, 1, 2, 3, 4 };
		final Binary binary = new Binary();
		binary.setContentType("PatientConsent").setContent(bin);

		DocumentManifest manifest = new DocumentManifest();
		CodeableConcept cc = new CodeableConcept();
		cc.addCoding().setSystem("mySystem").setCode("PatientDocument");
		manifest.setType(cc);
		manifest.setMasterIdentifier(new Identifier().setSystem("mySystem").setValue(UUID.randomUUID().toString()));
		manifest.addContent().setP(new Reference(binary));
		manifest.setStatus(Enumerations.DocumentReferenceStatus.CURRENT);

		String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(manifest);
		ourLog.info(encoded);
		assertThat(encoded, StringContainsInOrder.stringContainsInOrder(Arrays.asList("contained>", "<Binary", "</contained>")));

		DocumentManifest actual = ourCtx.newXmlParser().parseResource(DocumentManifest.class, encoded);
		assertEquals(1, actual.getContained().size());
		assertEquals(1, actual.getContent().size());

	/*
	 * If this fails, it's possibe the DocumentManifest structure is wrong: It should be
	 *
	 * @Child(name = "p", type = {Attachment.class, ValueSet.class}, order=1, min=1, max=1, modifier=false, summary=true)
	 */
		assertNotNull(((Reference) actual.getContent().get(0).getP()).getResource());
	}

	/**
	 * See #426
	 */
	@Test
	public void testParseExtensionWithIdType() {
		//@formatter:off
		String input =
			"<Patient xmlns=\"http://hl7.org/fhir\">\n" +
				"    <extension url=\"http://aaa.ch/fhir/Patient#mangedcare\">\n" +
				"        <extension url=\"http://aaa.ch/fhir/Patient#mangedcare-aaa-id\">\n" +
				"           <valueId value=\"mc1\"/>\n" +
				"        </extension>\n" +
				"    </extension>\n" +
				"    <identifier>\n" +
				"        <value value=\"ais111\"/>\n" +
				"    </identifier>\n" +
				"</Patient>";
		//@formatter:on
		Patient pt = ourCtx.newXmlParser().parseResource(Patient.class, input);

		List<Extension> extList = pt.getExtensionsByUrl("http://aaa.ch/fhir/Patient#mangedcare");
		extList = extList.get(0).getExtensionsByUrl("http://aaa.ch/fhir/Patient#mangedcare-aaa-id");
		Extension ext = extList.get(0);
		IdType value = (IdType) ext.getValue();
		assertEquals("mc1", value.getValueAsString());
	}

	/**
	 * See #426
	 *
	 * Value type of FOO isn't a valid datatype
	 */
	@Test
	public void testParseExtensionWithInvalidType() {
		//@formatter:off
		String input =
			"<Patient xmlns=\"http://hl7.org/fhir\">\n" +
				"    <extension url=\"http://aaa.ch/fhir/Patient#mangedcare\">\n" +
				"        <extension url=\"http://aaa.ch/fhir/Patient#mangedcare-aaa-id\">\n" +
				"           <valueFOO value=\"mc1\"/>\n" +
				"        </extension>\n" +
				"    </extension>\n" +
				"    <identifier>\n" +
				"        <value value=\"ais111\"/>\n" +
				"    </identifier>\n" +
				"</Patient>";
		//@formatter:on
		Patient pt = ourCtx.newXmlParser().parseResource(Patient.class, input);

		List<Extension> extList = pt.getExtensionsByUrl("http://aaa.ch/fhir/Patient#mangedcare");
		extList = extList.get(0).getExtensionsByUrl("http://aaa.ch/fhir/Patient#mangedcare-aaa-id");
		Extension ext = extList.get(0);
		IdType value = (IdType) ext.getValue();
		assertEquals(null, value);
	}

	/**
	 * See #342
	 */
	@Test(expected = DataFormatException.class)
	public void testParseInvalid() {
		ourCtx.newXmlParser().parseResource("FOO");
	}

	/**
	 * See #366
	 */
	@Test()
	public void testParseInvalidBoolean() {
		//@formatter:off
		String resource = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"   <active value=\"1\"/>\n" +
			"</Patient>";
		//@formatter:on

		IParser p = ourCtx.newXmlParser();

		try {
			p.parseResource(resource);
			fail();
		} catch (DataFormatException e) {
			assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"1\": Invalid boolean string: '1'", e.getMessage());
		}

		LenientErrorHandler errorHandler = new LenientErrorHandler();
		assertEquals(true, errorHandler.isErrorOnInvalidValue());
		errorHandler.setErrorOnInvalidValue(false);
		p.setParserErrorHandler(errorHandler);
	}

	@Test
	public void testParseInvalidTextualNumber() {
		Observation obs = new Observation();
		obs.setValue(new Quantity().setValue(1234));
		String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(obs);
		encoded = encoded.replace("1234", "\"1234\"");
		ourLog.info(encoded);
		ourCtx.newJsonParser().parseResource(encoded);
	}

	@Test
	public void testParseMetadata() throws Exception {
		//@formatter:off
		String bundle = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"   <total value=\"1\"/>\n" +
			"   <link>\n" +
			"      <relation value=\"self\"/>\n" +
			"      <url value=\"http://localhost:52788/Binary?_pretty=true\"/>\n" +
			"   </link>\n" +
			"   <entry>\n" +
			"      <fullUrl value=\"http://foo/fhirBase2/Patient/1/_history/2\"/>\n" +
			"      <resource>\n" +
			"         <Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"            <id value=\"1\"/>\n" +
			"            <meta>\n" +
			"               <versionId value=\"2\"/>\n" +
			"               <lastUpdated value=\"2001-02-22T09:22:33-07:00\"/>\n" +
			"            </meta>\n" +
			"            <birthDate value=\"2012-01-02\"/>\n" +
			"         </Patient>\n" +
			"      </resource>\n" +
			"      <search>\n" +
			"         <mode value=\"match\"/>\n" +
			"         <score value=\"0.123\"/>\n" +
			"      </search>\n" +
			"      <request>\n" +
			"         <method value=\"POST\"/>\n" +
			"         <url value=\"http://foo/Patient?identifier=value\"/>\n" +
			"      </request>\n" +
			"   </entry>\n" +
			"</Bundle>";
		//@formatter:on

		Bundle b = ourCtx.newXmlParser().parseResource(Bundle.class, bundle);
		assertEquals(1, b.getEntry().size());

		Bundle.BundleEntryComponent entry = b.getEntry().get(0);
		Patient pt = (Patient) entry.getResource();
		assertEquals("http://foo/fhirBase2/Patient/1/_history/2", pt.getIdElement().getValue());
		assertEquals("2012-01-02", pt.getBirthDateElement().getValueAsString());
		assertEquals("0.123", entry.getSearch().getScore().toString());
		assertEquals("match", entry.getSearch().getMode().toCode());
		assertEquals("POST", entry.getRequest().getMethod().toCode());
		assertEquals("http://foo/Patient?identifier=value", entry.getRequest().getUrl());
		assertEquals("2001-02-22T09:22:33-07:00", pt.getMeta().getLastUpdatedElement().getValueAsString());

		IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
		String reEncoded = p.encodeResourceToString(b);
		ourLog.info(reEncoded);

		compareXml(bundle, reEncoded);

	}

	@Test
	public void testParseMetaUpdatedDate() {
		//@formatter:off
		String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
			"   <id value=\"e2ee823b-ee4d-472d-b79d-495c23f16b99\"/>\n" +
			"   <meta>\n" +
			"      <lastUpdated value=\"2015-06-22T15:48:57.554-04:00\"/>\n" +
			"   </meta>\n" +
			"   <type value=\"searchset\"/>\n" +
			"   <base value=\"http://localhost:58109/fhir/context\"/>\n" +
			"   <total value=\"0\"/>\n" +
			"   <link>\n" +
			"      <relation value=\"self\"/>\n" +
			"      <url value=\"http://localhost:58109/fhir/context/Patient?_pretty=true\"/>\n" +
			"   </link>\n" +
			"</Bundle>";
		//@formatter:on
		Bundle b = ourCtx.newXmlParser().parseResource(Bundle.class, input);

		InstantType updated = b.getMeta().getLastUpdatedElement();
		assertEquals("2015-06-22T15:48:57.554-04:00", updated.getValueAsString());

	}

	@Test
	public void testParseNestedExtensionsInvalid() {
		//@formatter:off
		String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
			"   <birthDate value=\"2005-03-04\">\n" +
			"      <extension url=\"http://my.fancy.extension.url\">\n" +
			"         <valueString value=\"myvalue\"/>\n" +
			"         <extension url=\"http://my.fancy.extension.url\">\n" +
			"            <valueString value=\"myNestedValue\"/>\n" +
			"         </extension>\n" +
			"      </extension>\n" +
			"   </birthDate>\n" +
			"</Patient>";
		//@formatter:on

		try {
			ourCtx.newXmlParser().parseResource(Patient.class, input);
			fail();
		} catch (DataFormatException e) {
			assertThat(e.getMessage(), containsString("Extension (URL='http://my.fancy.extension.url') must not have both a value and other contained extensions"));
		}
	}

	/**
	 * See #163
	 */
	@Test
	public void testParseResourceType() {
		IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);

		// Patient
		Patient patient = new Patient();
		String patientId = UUID.randomUUID().toString();
		patient.setId(new IdType("Patient", patientId));
		patient.addName().addGiven("John").addFamily("Smith");
		patient.setGender(Enumerations.AdministrativeGender.MALE);
		patient.setBirthDateElement(new DateType("1987-04-16"));

		// Bundle
		Bundle bundle = new Bundle();
		bundle.setType(Bundle.BundleType.COLLECTION);
		bundle.addEntry().setResource(patient);

		String bundleText = xmlParser.encodeResourceToString(bundle);
		ourLog.info(bundleText);

		Bundle reincarnatedBundle = xmlParser.parseResource(Bundle.class, bundleText);
		Patient reincarnatedPatient = (Patient) reincarnatedBundle.getEntry().get(0).getResource();

		assertEquals("Patient", patient.getIdElement().getResourceType());
		assertEquals("Patient", reincarnatedPatient.getIdElement().getResourceType());
	}

	/**
	 * See #344
	 */
	@Test
	public void testParserIsCaseSensitive() {
		Observation obs = new Observation();
		SampledData data = new SampledData();
		data.setData("1 2 3");
		data.setOrigin((SimpleQuantity) new SimpleQuantity().setValue(0L));
		data.setPeriod(1000L);
		obs.setValue(data);

		IParser p = ourCtx.newXmlParser().setPrettyPrint(true).setParserErrorHandler(new StrictErrorHandler());
		String encoded = p.encodeResourceToString(obs);
		ourLog.info(encoded);

		p.parseResource(encoded);

		try {
			p.parseResource(encoded.replace("Observation", "observation"));
			fail();
		} catch (DataFormatException e) {
			assertEquals("DataFormatException at [[row,col {unknown-source}]: [1,1]]: Unknown resource type 'observation': Resource names are case sensitive, found similar name: 'Observation'",
				e.getMessage());
		}

		try {
			p.parseResource(encoded.replace("valueSampledData", "valueSampleddata"));
			fail();
		} catch (DataFormatException e) {
			assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Unknown element 'valueSampleddata' found during parse", e.getMessage());
		}
	}

	/**
	 * See #339
	 *
	 * https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing
	 */
	@Test
	public void testXxe() {
		//@formatter:off
		String input =
			"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" +
				"<!DOCTYPE foo [  " +
				"<!ELEMENT foo ANY >" +
				"<!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]>" +
				"<Patient xmlns=\"http://hl7.org/fhir\">" +
				"<text>" +
				"<div xmlns=\"http://www.w3.org/1999/xhtml\">TEXT &xxe; TEXT</div>" +
				"</text>" +
				"<address>" +
				"<line value=\"FOO\"/>" +
				"</address>" +
				"</Patient>";
		//@formatter:on

		ourLog.info(input);

		try {
			ourCtx.newXmlParser().parseResource(Patient.class, input);
			fail();
		} catch (DataFormatException e) {
			assertThat(e.toString(), containsString("Undeclared general entity"));
		}

	}

	@Test
	public void testBaseUrlFooResourceCorrectlySerializedInExtensionValueReference() {
		String refVal = "http://my.org/FooBar";

		Patient fhirPat = new Patient();
		fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));

		IParser parser = ourCtx.newXmlParser();

		String output = parser.encodeResourceToString(fhirPat);
		System.out.println("output: " + output);

		// Deserialize then check that valueReference value is still correct
		fhirPat = parser.parseResource(Patient.class, output);

		List<Extension> extlst = fhirPat.getExtensionsByUrl("x1");
		assertEquals(1, extlst.size());
		assertEquals(refVal, ((Reference) extlst.get(0).getValue()).getReference());
	}

	public static void compareXml(String content, String reEncoded) {
		Diff d = DiffBuilder.compare(Input.fromString(content))
			.withTest(Input.fromString(reEncoded))
			.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
			.checkForSimilar()
			.ignoreWhitespace()
			.ignoreComments()
			.withComparisonController(ComparisonControllers.Default)
			.build();

		assertTrue(d.toString(), !d.hasDifferences());
	}

	@ResourceDef(name = "Patient")
	public static class TestPatientFor327 extends Patient {

		private static final long serialVersionUID = 1L;

		@Child(name = "testCondition")
		@ca.uhn.fhir.model.api.annotation.Extension(url = "testCondition", definedLocally = true, isModifier = false)
		private List<Reference> testConditions = null;

		public List<Reference> getConditions() {
			return this.testConditions;
		}

		public void setCondition(List<Reference> ref) {
			this.testConditions = ref;
		}
	}

	private Matcher<? super String> stringContainsInOrder(java.lang.String... substrings) {
		return Matchers.stringContainsInOrder(Arrays.asList(substrings));
	}

	private Matcher<? super String> stringContainsInOrder(List<String> substrings) {
		return Matchers.stringContainsInOrder(substrings);
	}

}
