fix document validation + add questionnaire validation tests

This commit is contained in:
Grahame Grieve 2019-10-25 13:25:52 +11:00
parent 5afc745424
commit 22f4a5a58f
12 changed files with 996 additions and 11 deletions

View File

@ -0,0 +1,162 @@
package org.hl7.fhir.dstu3.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.hl7.fhir.dstu3.formats.IParser.OutputStyle;
import org.hl7.fhir.dstu3.formats.JsonParser;
import org.hl7.fhir.dstu3.formats.XmlParser;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.DomainResource;
import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.utilities.Utilities;
public class R3TEchnicalCorrectionProcessor {
public static void main(String[] args) throws FileNotFoundException, IOException {
new R3TEchnicalCorrectionProcessor().execute(args[0], args[1]);
}
private void execute(String src, String packageRoot) throws FileNotFoundException, IOException {
System.out.println("Loading resources from "+src);
List<Resource> resources = new ArrayList<>();
Map<String, Resource> definitions = new HashMap<>();
for (File f : new File(src).listFiles()) {
if (f.getName().endsWith(".xml") && !(f.getName().endsWith("warnings.xml") || f.getName().endsWith(".diff.xml"))) {
try {
Resource r = new XmlParser().parse(new FileInputStream(f));
if (f.getName().contains("canonical")) {
resources.add(r);
}
if (Utilities.existsInList(f.getName(), "conceptmaps.xml", "dataelements.xml", "extension-definitions.xml", "profiles-others.xml", "profiles-resources.xml",
"profiles-types.xml", "search-parameters.xml", "v2-tables.xml", "v3-codesystems.xml", "valuesets.xml")) {
definitions.put(f.getName(), r);
}
r.setUserData("path", f.getName().substring(0, f.getName().indexOf(".")));
// FileUtils.copyFile(f, new File(f.getAbsolutePath()+"1"));
// FileUtils.copyFile(f, new File(f.getAbsolutePath()+"2"));
} catch (Exception e) {
System.out.println("Unable to load "+f.getName()+": "+e.getMessage());
}
}
if (f.getName().endsWith(".json") && !(f.getName().endsWith("schema.json") || f.getName().endsWith(".diff.json"))) {
try {
// new JsonParser().parse(new FileInputStream(f));
// FileUtils.copyFile(f, new File(f.getAbsolutePath()+"1"));
// FileUtils.copyFile(f, new File(f.getAbsolutePath()+"2"));
} catch (Exception e) {
System.out.println("Unable to load "+f.getName()+": "+e.getMessage());
}
}
}
System.out.println(Integer.toString(resources.size())+" resources");
System.out.println(Integer.toString(definitions.size())+" resources");
produceExamplesXml(resources, src);
produceDefinitionsXml(definitions, src);
produceExamplesJson(resources, src);
produceDefinitionsJson(definitions, src);
for (Resource r : definitions.values()) {
if (r instanceof Bundle) {
Bundle bnd = (Bundle) r;
for (BundleEntryComponent be : bnd.getEntry()) {
resources.add(be.getResource());
}
}
}
extractToPackageMaster(resources, packageRoot);
System.out.println("Done");
}
private void produceDefinitionsXml(Map<String, Resource> definitions, String dest) throws IOException {
for (String n : definitions.keySet()) {
File f = new File(Utilities.path(dest, "definitions.xml", n));
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(f), definitions.get(n));
}
}
private void produceDefinitionsJson(Map<String, Resource> definitions, String dest) throws IOException {
for (String n : definitions.keySet()) {
File f = new File(Utilities.path(dest, "definitions.json", Utilities.changeFileExt(n, ".json")));
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(f), definitions.get(n));
}
}
private void produceExamplesJson(List<Resource> resources, String dest) throws FileNotFoundException, IOException {
for (Resource r : resources) {
String n = r.fhirType().toLowerCase()+"-"+r.getUserString("path");
if (!r.getId().equals(r.getUserString("path"))) {
n = n+"("+r.getId()+")";
}
File f = new File(Utilities.path(dest, "examples-json", n+".json"));
new JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(f), r);
}
}
private void produceExamplesXml(List<Resource> resources, String dest) throws FileNotFoundException, IOException {
for (Resource r : resources) {
String n = r.fhirType().toLowerCase()+"-"+r.getUserString("path");
if (!r.getId().equals(r.getUserString("path"))) {
n = n+"("+r.getId()+")";
}
File f = new File(Utilities.path(dest, "examples", n+".xml"));
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(f), r);
}
}
private void extractToPackageMaster(List<Resource> list, String root) throws IOException, FHIRFormatError {
System.out.println("Updating Packages Master");
String corePath = Utilities.path(root, "hl7.fhir.r3.core", "package");
String examplesPath = Utilities.path(root, "hl7.fhir.r3.examples", "package");
String elementsPath = Utilities.path(root, "hl7.fhir.r3.elements", "package");
int coreTotal = new File(corePath).list().length-1;
int examplesTotal = new File(examplesPath).list().length-1;
int elementsTotal = new File(elementsPath).list().length-1;
int coreCount = 0;
int examplesCount = 0;
int elementsCount = 0;
for (Resource r : list) {
String n = r.fhirType()+"-"+r.getId()+".json";
FileOutputStream dst = null;
if (n.startsWith("DataElement-")) {
elementsCount++;
dst = new FileOutputStream(Utilities.path(elementsPath, n));
new JsonParser().setOutputStyle(OutputStyle.NORMAL).compose(dst, r);
} else {
dst = new FileOutputStream(Utilities.path(examplesPath, n));
new JsonParser().setOutputStyle(OutputStyle.NORMAL).compose(dst, r);
if (isCoreResource(r.fhirType())) {
coreCount++;
DomainResource dr = (DomainResource) r;
dr.setText(null);
new JsonParser().setOutputStyle(OutputStyle.NORMAL).compose(new FileOutputStream(Utilities.path(corePath, n)), r);
}
}
}
System.out.println(" Core @ "+corePath+": Replaced "+coreCount+" of "+coreTotal);
System.out.println(" Examples @ "+examplesPath+": Replaced "+examplesCount+" of "+examplesTotal);
System.out.println(" Elements @ "+elementsPath+": Replaced "+elementsCount+" of "+elementsTotal);
}
private boolean isCoreResource(String rt) {
return Utilities.existsInList(rt, "CapabilityStatement", "CodeSystem", "CompartmentDefinition", "ConceptMap", "NamingSystem", "OperationDefinition", "SearchParameter", "StructureDefinition", "StructureMap", "ValueSet");
}
}

View File

@ -91,7 +91,7 @@ public abstract class ParserBase {
protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError {
if (ns == null) {
logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no namespace)", IssueSeverity.FATAL);
logError(line, col, name, IssueType.STRUCTURE, "This '"+name+"' cannot be parsed as a FHIR object (no namespace)", IssueSeverity.FATAL);
return null;
}
if (name == null) {

View File

@ -2306,6 +2306,8 @@ public class ElementDefinition extends BackboneType implements ICompositeType {
return "integer";
if ("xsd:decimal OR xsd:double".equals(s))
return "decimal";
if ("xsd:decimal".equals(s))
return "decimal";
if ("xsd:base64Binary".equals(s))
return "base64Binary";
if ("xsd:positiveInteger".equals(s))

View File

@ -1001,7 +1001,7 @@ public class TurtleTests {
}
@Test
public void test_turtle_syntax_bad_number_dot_in_anon() throws Exception {
doTest(TestingUtilities.resourceNameToFile("turtle", "turtle-syntax-bad-number-dot-in-anon.ttl"), true);
doTest(TestingUtilities.resourceNameToFile("turtle", "turtle-syntax-bad-number-dot-in-anon.ttl"), false);
}
@Test
public void test_turtle_syntax_bad_pname_01() throws Exception {

View File

@ -131,6 +131,9 @@ public class EnableWhenEvaluator {
* @return
*/
public boolean isQuestionEnabled(QuestionnaireItemComponent qitem, QStack qstack) {
if (hasExpressionExtension(qitem)) {
throw new Error("Not Done Yet");
}
if (!qitem.hasEnableWhen()) {
return true;
}
@ -142,6 +145,12 @@ public class EnableWhenEvaluator {
}
private boolean hasExpressionExtension(QuestionnaireItemComponent qitem) {
return qitem.hasExtension("http://phr.kanta.fi/StructureDefinition/fiphr-ext-questionnaire-enablewhen") || // finnish extension
qitem.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); // sdc extension
}
public boolean checkConditionResults(List<EnableWhenResult> evaluationResults, QuestionnaireItemComponent questionnaireItem) {
if ((questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ANY) || evaluationResults.size() == 1){
return evaluationResults.stream().anyMatch(EnableWhenResult::isEnabled);

View File

@ -3905,7 +3905,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (ref != null && !Utilities.noString(reference)) {
Element target = resolveInBundle(entries, reference, fullUrl, type, id);
rule(errors, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), target != null, "Unable to resolve the target of the reference in the bundle (" + name + ")");
rule(errors, IssueType.INVALID, ref.line(), ref.col(), stack.addToLiteralPath("reference"), target != null, "Can't find '"+reference+"' in the bundle (" + name + ")");
}
}
@ -3925,13 +3925,47 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
// first entry must be a composition
if (rule(errors, IssueType.INVALID, composition.line(), composition.col(), stack.getLiteralPath(), composition.getType().equals("Composition"),
"The first entry in a document must be a composition")) {
// the composition subject and section references must resolve in the bundle
Element elem = composition.getNamedChild("subject");
if (rule(errors, IssueType.INVALID, composition.line(), composition.col(), stack.getLiteralPath(), elem != null, "A document composition must have a subject"))
validateBundleReference(errors, entries, elem, "Composition Subject", stack.push(elem, -1, null, null), fullUrl, "Composition", id);
// the composition subject etc references must resolve in the bundle
validateDocumentReference(errors, entries, composition, stack, fullUrl, id, false, "subject", "Composition");
validateDocumentReference(errors, entries, composition, stack, fullUrl, id, true, "author", "Composition");
validateDocumentReference(errors, entries, composition, stack, fullUrl, id, false, "encounter", "Composition");
validateDocumentReference(errors, entries, composition, stack, fullUrl, id, false, "custodian", "Composition");
validateDocumentSubReference(errors, entries, composition, stack, fullUrl, id, "Composition", "attester", false, "party");
validateDocumentSubReference(errors, entries, composition, stack, fullUrl, id, "Composition", "event", true, "detail");
validateSections(errors, entries, composition, stack, fullUrl, id);
}
}
public void validateDocumentSubReference(List<ValidationMessage> errors, List<Element> entries, Element composition, NodeStack stack, String fullUrl, String id, String title, String parent, boolean repeats, String propName) {
List<Element> list = new ArrayList<>();
composition.getNamedChildren(parent, list);
int i = 1;
for (Element elem : list) {
validateDocumentReference(errors, entries, elem, stack.push(elem, i, null, null), fullUrl, id, repeats, propName, title+"."+parent);
i++;
}
}
public void validateDocumentReference(List<ValidationMessage> errors, List<Element> entries, Element composition, NodeStack stack, String fullUrl, String id, boolean repeats, String propName, String title) {
if (repeats) {
List<Element> list = new ArrayList<>();
composition.getNamedChildren(propName, list);
int i = 1;
for (Element elem : list) {
validateBundleReference(errors, entries, elem, title+"."+propName, stack.push(elem, i, null, null), fullUrl, "Composition", id);
i++;
}
} else {
Element elem = composition.getNamedChild(propName);
if (elem != null) {
validateBundleReference(errors, entries, elem, title+"."+propName, stack.push(elem, -1, null, null), fullUrl, "Composition", id);
}
}
}
// rule(errors, IssueType.INVALID, bundle.line(), bundle.col(), "Bundle", !"urn:guid:".equals(base), "The base 'urn:guid:' is not valid (use urn:uuid:)");
// rule(errors, IssueType.INVALID, entry.line(), entry.col(), localStack.getLiteralPath(), !"urn:guid:".equals(ebase), "The base 'urn:guid:' is not valid");
// rule(errors, IssueType.INVALID, entry.line(), entry.col(), localStack.getLiteralPath(), !Utilities.noString(base) || !Utilities.noString(ebase), "entry
@ -4590,11 +4624,23 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
private void validateSections(List<ValidationMessage> errors, List<Element> entries, Element focus, NodeStack stack, String fullUrl, String id) {
List<Element> sections = new ArrayList<Element>();
focus.getNamedChildren("entry", sections);
int i = 0;
focus.getNamedChildren("section", sections);
int i = 1;
for (Element section : sections) {
NodeStack localStack = stack.push(section, 1, null, null);
validateBundleReference(errors, entries, section.getNamedChild("content"), "Section Content", localStack, fullUrl, "Composition", id);
NodeStack localStack = stack.push(section, i, null, null);
// technically R4+, but there won't be matches from before that
validateDocumentReference(errors, entries, section, stack, fullUrl, id, false, "author", "Section");
validateDocumentReference(errors, entries, section, stack, fullUrl, id, false, "focus", "Section");
List<Element> sectionEntries = new ArrayList<Element>();
section.getNamedChildren("entry", sectionEntries);
int j = 1;
for (Element sectionEntry : sectionEntries) {
NodeStack localStack2 = localStack.push(sectionEntry, j, null, null);
validateBundleReference(errors, entries, sectionEntry, "Section Entry", localStack2, fullUrl, "Composition", id);
j++;
}
validateSections(errors, entries, section, localStack, fullUrl, id);
i++;
}

View File

@ -0,0 +1,641 @@
{
"resourceType" : "Bundle",
"id" : "9e11848b-0e37-4bc6-92cf-153b0917cd22",
"identifier" : {
"value" : "889977665544",
"system" : "http://spms.min-saude.pt/SClinico/code"
},
"type" : "document",
"entry" : [
{
"fullUrl" : "http://spms.min-saude.pt/fhir/Composition/27eab09d-74bc-4ad3-95b1-d890b7db4c2b",
"resource" : {
"resourceType" : "Composition",
"id" : "27eab09d-74bc-4ad3-95b1-d890b7db4c2b",
"identifier" : {
"system" : "http://spms.min-saude.pt/SClinico/code",
"value" : "889977665544"
},
"status" : "final",
"type" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "18842-5",
"display" : "Discharge Summary"
}
]
},
"subject" : {
"reference" : "Patient/94615767-9ba1-482c-8930-fdda1a0baea8"
},
"encounter" : {
"reference" : "Encounter/17bcea80-37a6-43ec-a40c-427ab904edd8"
},
"date" : "2019-10-02T16:48:19.000+00:00",
"author" : [
{
"reference" : "Practitioner/88b07e2d-73dc-4b87-b1cf-c0d0eddd0e5c"
},
{
"reference" : "Practitioner/09b68ca1-4088-48bd-9768-1c8bf6118607"
},
{
"reference" : "Practitioner/ca85c061-8c81-4ff8-8188-cae8d231d872"
},
{
"reference" : "Practitioner/46d2e8af-e3fb-408d-a042-43c3561291e3"
}
],
"attester" : [
{
"mode" : ["personal"],
"party" : {
"reference" : "Practitioner/46d2e8af-e3fb-408d-a042-43c3561291e3"
}
}
],
"title" : "Nota de alta de internamento",
"custodian" : {
"reference" : "Organization/08748631-6f66-46fd-a8c5-528b574dc33d"
},
"event" : [
{
"detail" : [
{
"reference" : "Encounter/17bcea80-37a6-43ec-a40c-427ab904edd8"
}
]
}
],
"section" : [
{
"title" : "Allergies",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "48765-2",
"display" : "Allergies"
}
]
},
"entry" : [
{
"reference" : "AllergyIntolerance/4f9ad961-d5f1-4888-aa6c-05d003fce450"
}
]
},
{
"title" : "Hospital course Narrative",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "8648-8",
"display" : "Hospital course Narrative"
}
]
},
"entry" : [
{
"reference" : "Observation/5da5de2d-93c8-40db-90b6-7d1763fed7f5"
}
]
},
{
"title" : "Discharge diagnosis Narrative",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "78375-3",
"display" : "Discharge diagnosis Narrative"
}
]
},
"entry" : [
{
"reference" : "Encounter/17bcea80-37a6-43ec-a40c-427ab904edd8"
}
]
},
{
"title" : "Discharge medications Narrative",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "75311-1",
"display" : "Discharge medications Narrative"
}
]
},
"entry" : [
{
"reference" : "MedicationRequest/b684690b-bb71-45b3-9779-88fd89f1d0b5"
}
]
},
{
"title" : "Admission diagnosis (narrative)",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "42347-5",
"display" : "Admission diagnosis (narrative)"
}
]
},
"entry" : [
{
"reference" : "Encounter/17bcea80-37a6-43ec-a40c-427ab904edd8"
}
]
},
{
"title" : "Medications on admission (narrative)",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "42346-7",
"display" : "Medications on admission (narrative)"
}
]
},
"entry" : [
{
"reference" : "MedicationAdministration/199a4838-e1ba-4408-8ca2-da6a826373da"
},
{
"reference" : "MedicationAdministration/d6c8c9b2-da4e-4aac-9200-b79b05480402"
},
{
"reference" : "MedicationAdministration/4db8b223-8c95-4554-9e7f-86906a6c80da"
},
{
"reference" : "MedicationAdministration/d8adcea3-f539-4dcb-baef-f049bb5eae33"
}
]
},
{
"title" : "Discharge diet (narrative)",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "42344-2",
"display" : "Discharge diet (narrative)"
}
]
},
"entry" : [
{
"reference" : "Observation/20b06357-2287-4246-b637-0c0c510ac2d5"
}
]
},
{
"title" : "History of Present illness Narrative",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "10164-2",
"display" : "History of Present illness Narrative"
}
]
},
"entry" : [
{
"reference" : "Observation/aaa443d5-222d-4e4b-8291-155750ba9bf6"
}
]
},
{
"title" : "Plan of Care",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "18776-5",
"display" : "Plan of care"
}
]
},
"section" : [
{
"title" : "Proposta de monitorização e tratamento",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "PMT",
"display" : "Proposta de monitorização e tratamento"
}
]
},
"entry" : [
{
"reference" : "Observation/cfddbb48-045d-4853-b4f4-e18a2d72701f"
}
]
},
{
"title" : "Orientação/agendamentos",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "ORI",
"display" : "Orientação/agendamentos"
}
]
},
"entry" : [
{
"reference" : "Appointment/ac28d16e-0631-4e9b-9bbf-873339010e29"
},
{
"reference" : "Appointment/b54abdba-8f77-4900-9c79-bda7e0348eed"
},
{
"reference" : "Appointment/e1574ddd-7a92-42cd-8a6f-733180dd1291"
},
{
"reference" : "Appointment/5c5af0ca-ccc6-4821-91eb-ef32b7d483e6"
},
{
"reference" : "Appointment/42e5f192-32aa-4eb2-a90e-7e3ff2f8d701"
},
{
"reference" : "Appointment/c960cc20-15fb-4ef9-867d-d13c96750ea8"
},
{
"reference" : "Appointment/f1d8748c-057e-437b-a8b2-5f7642250e5e"
}
]
},
{
"title" : "Meios complementares de diagnóstico marcados",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "MCDTM",
"display" : "Meios complementares de diagnóstico marcados"
}
]
},
"emptyReason" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list-empty-reason",
"code" : "not-found",
"display" : "Not Found"
}
],
"text" : "Não foram encontrados registos para este utente"
}
}
]
},
{
"title" : "Functional status assessment note",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "47420-5",
"display" : "Functional status assessment note"
}
]
},
"section" : [
{
"title" : "Focos de diagnóstico de enfermagem",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "FDE",
"display" : "Focos de diagnóstio de enfermagem"
}
]
},
"entry" : [
{
"reference" : "Condition/3d4dcb01-5e84-4de3-bfd1-2c7a873acd74"
}
]
},
{
"title" : "Atitudes Terapêuticas",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "ATI",
"display" : "Atitudes terapêuticas"
}
]
},
"entry" : [
{
"reference" : "Procedure/1cdba079-e745-4ff3-bfd6-6fae81238be8"
},
{
"reference" : "Procedure/42077cf6-64c0-4309-ab0d-bb1859da03ae"
},
{
"reference" : "Procedure/85b5f07c-f1cf-4038-be23-5ad2b9d89e92"
},
{
"reference" : "Procedure/2afedeb5-0c0f-4e0a-a506-93f03c8bd382"
}
]
}
]
},
{
"title" : "History of Procedures Document",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "47519-4",
"display" : "History of Procedures Document"
}
]
},
"section" : [
{
"title" : "Dispositivos implantáveis",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "DIS",
"display" : "Dispositivos implantáveis"
}
]
},
"entry" : [
{
"reference" : "Device/5b237d94-0ae3-49a2-9a8a-ef39607cc68d"
}
]
},
{
"title" : "Intervenções Cirúrgicas",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "INT",
"display" : "Intervenções cirúrgicas"
}
]
},
"entry" : [
{
"reference" : "Procedure/59b211c5-32aa-4c28-91df-d81de43b1bd1"
}
]
},
{
"title" : "Ventilação Mecânica",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "VEN",
"display" : "Ventilação mecânica"
}
]
},
"entry" : [
{
"reference" : "Procedure/ce38198b-f2e1-4625-85d7-5c58a9eb8c94"
},
{
"reference" : "Procedure/4a42b0a8-d198-42fc-9658-d24a2214fc8d"
},
{
"reference" : "Procedure/0ee5087f-d047-453a-afdc-d6eccba2d2df"
}
]
},
{
"title" : "Infeção nosocomial",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "INF",
"display" : "Infeção nosocomial"
}
]
},
"entry" : [
{
"reference" : "Procedure/a96a4c64-976a-42e5-938a-f54b844e07b0"
},
{
"reference" : "Procedure/b18f9160-91eb-4d19-b7d2-25dc4e66cc2c"
}
]
},
{
"title" : "Meios complementares de diagnósticos efetuados",
"code" : {
"coding" : [
{
"system" : "http://spms.min-saude.pt/valueset-list",
"code" : "MCDTE",
"display" : "Meios complementares de diagnósticos efetuados"
}
]
},
"entry" : [
{
"reference" : "ProcedureRequest/47d0cf17-65aa-4f65-abb0-1f4e4cf53f35"
},
{
"reference" : "ProcedureRequest/e8814151-03c6-4f85-9caf-a8ea606acb5c"
},
{
"reference" : "ProcedureRequest/1b1ae576-fae6-425c-a85b-78e222b269f7"
},
{
"reference" : "ProcedureRequest/7ed52dda-afde-4b4a-bb60-0b5600d598bd"
},
{
"reference" : "ProcedureRequest/8a426c75-119e-441e-bfea-55fdc50118ba"
},
{
"reference" : "ProcedureRequest/82a006cd-939b-4dde-8982-5f875ed862cc"
},
{
"reference" : "ProcedureRequest/cc8b9f10-cd3b-4240-8352-b8346cf48205"
},
{
"reference" : "ProcedureRequest/8b7fbb19-5ca1-4f47-8b0b-6fedcc543b5f"
},
{
"reference" : "ProcedureRequest/c8e08048-0c43-42b9-a611-6c92705a910d"
},
{
"reference" : "ProcedureRequest/26587c9f-5041-4313-ac03-ab8feda7951a"
},
{
"reference" : "ProcedureRequest/d65a5ce6-97fe-4959-9660-6c096d70b3a1"
},
{
"reference" : "ProcedureRequest/018aea83-70f9-44db-908b-bd8a0f475cd3"
},
{
"reference" : "ProcedureRequest/3346f637-c83f-4a3f-a82d-fbfce6286f3d"
},
{
"reference" : "ProcedureRequest/38ca8f90-71b2-44d9-a6cb-97aaf2df8781"
},
{
"reference" : "ProcedureRequest/c9320c07-569c-413f-8ffa-ef0fdaacac23"
},
{
"reference" : "ProcedureRequest/b4c2ec41-e1fe-43be-9ea4-97f34deca878"
},
{
"reference" : "ProcedureRequest/921f8560-5eb5-46fa-8dcd-0972756f5880"
},
{
"reference" : "ProcedureRequest/7de5bf65-09a5-4be8-8edb-9e909296e8e0"
},
{
"reference" : "ProcedureRequest/ff40f491-2a57-44ee-be62-19c63a5e5481"
},
{
"reference" : "ProcedureRequest/a2c80ea2-9b8d-46ce-a846-1b5b6a98d2a6"
},
{
"reference" : "ProcedureRequest/c9daa080-ef42-4b67-b252-566c4a334f81"
},
{
"reference" : "ProcedureRequest/206615ca-448a-418f-a287-96cb9e4ba4c4"
},
{
"reference" : "ProcedureRequest/307bc183-46fc-44f5-930d-af9602573204"
},
{
"reference" : "ProcedureRequest/a8ae7ec5-e2e4-402b-b578-4f52de17865f"
},
{
"reference" : "ProcedureRequest/43dd4257-cd53-4cba-a851-beec3730c98f"
}
]
}
]
},
{
"title" : "Review of systems Narrative - Reporte",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "10187-3",
"display" : "Review of systems Narrative Reporte"
}
]
},
"entry" : [
{
"reference" : "Observation/74f5c1f7-e6d9-4cac-bff8-5f22bbbdd501"
},
{
"reference" : "Observation/5957c0e2-ad3c-43e0-b45e-c002d2b45f05"
}
]
},
{
"title" : "Administrative information",
"code" : {
"coding" : [
{
"system" : "http://loinc.org",
"code" : "87504-7",
"display" : "Administrative information"
}
]
},
"entry" : [
{
"reference" : "Patient/94615767-9ba1-482c-8930-fdda1a0baea8"
},
{
"reference" : "Encounter/17bcea80-37a6-43ec-a40c-427ab904edd8"
},
{
"reference" : "List/0f1eedb7-9d71-456b-b228-e910a9723dd6"
}
]
}
]
}
},
{
"fullUrl" : "http://spms.min-saude.pt/fhir/Patient/94615767-9ba1-482c-8930-fdda1a0baea8",
"resource" : {
"resourceType" : "Patient",
"id" : "94615767-9ba1-482c-8930-fdda1a0baea8",
"identifier" : [
{
"type" : {
"coding" : [
{
"system" : "http://hl7.org/fhir/v2/0203",
"code" : "HC",
"display" : "Health Card Number"
}
],
"text" : "NNU"
},
"system" : "http://spms.min-saude.pt/rnu/identifiers/patient-id",
"value" : "383816471"
},
{
"type" : {
"coding" : [
{
"system" : "http://hl7.org/fhir/v2/0203",
"code" : "MR",
"display" : "Medical Record Number"
}
],
"text" : "Número do Processo"
},
"system" : "https://www.sns.gov.pt/hospitalfacilities/1137006/identifiers/patient-id",
"value" : "99149257"
}
],
"name" : [
{
"text" : "MARTIM RICARDO FERREIRA",
"given" : [
"RICARDO",
"FERREIRA"
],
"family" : "MARTIM"
}
],
"gender" : "male",
"birthDate" : "1943-11-24"
}
}
]
}

View File

@ -200,6 +200,11 @@
},
"fhirpath-null.json": {
"errorCount": 1
},
"Bundle.document.json": {
"version" : "3.0",
"errorCount": 68,
"errors-for-debugging" : ["68 errors to do with things not found in the bundle"],
},
"qr-ex.json": {
"questionnaire": "q-ex.json",
@ -653,6 +658,18 @@
"questionnaire": "questionnaire-enableWhen-test.xml",
"errorCount": 0
},
"questionnaireResponse-enableWhen-test-fail.xml": {
"questionnaire": "questionnaire-enableWhen-test.xml",
"errorCount": 1
},
"questionnaireResponse-enableWhenEx-test.xml": {
"questionnaire": "questionnaire-enableWhenEx-test.xml",
"errorCount": 0
},
"questionnaireResponse-enableWhenEx-test-fail.xml": {
"questionnaire": "questionnaire-enableWhenEx-test.xml",
"errorCount": 1
},
"questionnaireResponse-enableWhen-test-nested.xml": {
"questionnaire": "questionnaire-enableWhen-test-nested.xml",
"errorCount": 2

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<Questionnaire xmlns="http://hl7.org/fhir">
<id value="questionnaire-enableWhen-test" />
<language value="en-US" />
<text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<p>enableWhen test</p>
</div>
</text>
<url value="http://hl7.org/fhir/us/hai/Questionnaire/questionnaire-enableWhenEx-test" />
<status value="draft" />
<item>
<linkId value="condition" />
<text value="condition" />
<type value="boolean" />
<required value="true" />
<repeats value="false" />
</item>
<item>
<extension url="http://phr.kanta.fi/StructureDefinition/fiphr-ext-questionnaire-enablewhen">
<valueString value="QuestionnaireResponse.descendants().select(item).where(linkId='condition').answer.value.ofType('boolean')" />
</extension>
<linkId value="enable-when" />
<text value="enable when condition true" />
<type value="boolean" />
<required value="true" />
<repeats value="false" />
</item>
</Questionnaire>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<QuestionnaireResponse xmlns="http://hl7.org/fhir">
<id value="questionnaireResponse-enableWhen-test" />
<text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<p>enableWhen test response</p>
</div>
</text>
<questionnaire value="http://hl7.org/fhir/us/hai/Questionnaire/questionnaire-enableWhen-test" />
<status value="completed" />
<item>
<linkId value="condition" />
<text value="condition" />
<answer>
<valueBoolean value="false" />
</answer>
</item>
<item>
<linkId value="enable-when" />
<text value="enable when condition true" />
<answer>
<valueBoolean value="false" />
</answer>
</item>
</QuestionnaireResponse>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<QuestionnaireResponse xmlns="http://hl7.org/fhir">
<id value="questionnaireResponse-enableWhen-test" />
<text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<p>enableWhen test response</p>
</div>
</text>
<questionnaire value="http://hl7.org/fhir/us/hai/Questionnaire/questionnaire-enableWhenEx-test" />
<status value="completed" />
<item>
<linkId value="condition" />
<text value="condition" />
<answer>
<valueBoolean value="false" />
</answer>
</item>
<item>
<linkId value="enable-when" />
<text value="enable when condition true" />
<answer>
<valueBoolean value="false" />
</answer>
</item>
</QuestionnaireResponse>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<QuestionnaireResponse xmlns="http://hl7.org/fhir">
<id value="questionnaireResponse-enableWhen-test" />
<text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<p>enableWhen test response</p>
</div>
</text>
<questionnaire value="http://hl7.org/fhir/us/hai/Questionnaire/questionnaire-enableWhenEx-test" />
<status value="completed" />
<item>
<linkId value="condition" />
<text value="condition" />
<answer>
<valueBoolean value="true" />
</answer>
</item>
<item>
<linkId value="enable-when" />
<text value="enable when condition true" />
<answer>
<valueBoolean value="false" />
</answer>
</item>
</QuestionnaireResponse>