Merge pull request #44 from lmckenzi/multi-targetprofiles-per-same-resource
1. Cleaned up test cases to work after version changes in R5 (not sur…
This commit is contained in:
commit
90f8b829f2
|
@ -405,7 +405,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
}
|
||||
StructureDefinition sd = null;
|
||||
if (profile.startsWith("#")) {
|
||||
if (!rule(errors, IssueType.INVALID, element.line(), element.col(), path, sd != null, "StructureDefinition reference \"{0}\" is local, but there is not local context", profile)) {
|
||||
if (!rule(errors, IssueType.INVALID, element.line(), element.col(), path, containingProfile != null, "StructureDefinition reference \"{0}\" is local, but there is not local context", profile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1863,33 +1863,62 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// we validate as much as we can. First, can we infer a type from the profile?
|
||||
if (!type.hasTargetProfile() || type.hasTargetProfile("http://hl7.org/fhir/StructureDefinition/Resource"))
|
||||
ok = true;
|
||||
else for (UriType u : type.getTargetProfile()) {
|
||||
else {
|
||||
List<String> candidateProfiles = new ArrayList<String>();
|
||||
for (UriType u : type.getTargetProfile()) {
|
||||
String pr = u.getValue();
|
||||
|
||||
String bt = getBaseType(profile, pr);
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + bt);
|
||||
if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, bt != null, "Unable to resolve the profile reference '" + pr + "'")) {
|
||||
b.append(bt);
|
||||
ok = bt.equals(ft);
|
||||
if (ok && we!=null && pol.checkValid()) {
|
||||
doResourceProfile(hostContext, we, pr, errors, stack.push(we, -1, null, null), path, element, profile);
|
||||
if (bt.equals(ft)) {
|
||||
ok = true;
|
||||
if (we!=null && pol.checkValid())
|
||||
candidateProfiles.add(pr);
|
||||
}
|
||||
} else
|
||||
ok = true; // suppress following check
|
||||
if (ok && type.hasAggregation()) {
|
||||
boolean modeOk;
|
||||
}
|
||||
}
|
||||
HashMap<String, List<ValidationMessage>> goodProfiles = new HashMap<String, List<ValidationMessage>>();
|
||||
List<List<ValidationMessage>> badProfiles = new ArrayList<List<ValidationMessage>>();
|
||||
List<String> profiles = new ArrayList<String>();
|
||||
if (!candidateProfiles.isEmpty()) {
|
||||
for (String pr: candidateProfiles) {
|
||||
profiles.add(pr);
|
||||
List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
|
||||
doResourceProfile(hostContext, we, pr, profileErrors, stack.push(we, -1, null, null), path, element, profile);
|
||||
|
||||
if (hasErrors(profileErrors))
|
||||
badProfiles.add(profileErrors);
|
||||
else
|
||||
goodProfiles.put(pr, profileErrors);
|
||||
if (type.hasAggregation()) {
|
||||
boolean modeOk = false;
|
||||
for (Enumeration<AggregationMode> mode : type.getAggregation()) {
|
||||
if (mode.getValue().equals(AggregationMode.CONTAINED) && refType.equals("contained"))
|
||||
ok = true;
|
||||
modeOk = true;
|
||||
else if (mode.getValue().equals(AggregationMode.BUNDLED) && refType.equals("bundled"))
|
||||
ok = true;
|
||||
modeOk = true;
|
||||
else if (mode.getValue().equals(AggregationMode.REFERENCED) && (refType.equals("bundled")||refType.equals("remote")))
|
||||
ok = true;
|
||||
modeOk = true;
|
||||
}
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, modeOk, "Reference is " + refType + " which isn't supported by the specified aggregation mode(s) for the reference");
|
||||
}
|
||||
}
|
||||
if (goodProfiles.size()==1) {
|
||||
errors.addAll(goodProfiles.values().iterator().next());
|
||||
} else if (goodProfiles.size()==0) {
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size()==1, "Unable to find matching profile among choices: " + StringUtils.join("; ", profiles));
|
||||
for (List<ValidationMessage> messages : badProfiles) {
|
||||
errors.addAll(messages);
|
||||
}
|
||||
} else {
|
||||
warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, "Found multiple matching profiles among choices: " + StringUtils.join("; ", goodProfiles.keySet()));
|
||||
for (List<ValidationMessage> messages : goodProfiles.values()) {
|
||||
errors.addAll(messages);
|
||||
}
|
||||
}
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok, "Reference is " + refType + " which isn't supported by the specified aggregation mode(s) for the reference");
|
||||
}
|
||||
if (ok)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok && type.getCode().equals("*")) {
|
||||
|
@ -4001,14 +4030,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
|
|||
if (rule(errors, IssueType.STRUCTURE, ei.line(), ei.col(), ei.path, p != null, "Unknown profile " + typeProfile)) {
|
||||
List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
|
||||
validateElement(hostContext, profileErrors, p, getElementByTail(p, tail), profile, ei.definition, resource, ei.element, type, localStack, thisIsCodeableConcept, checkDisplay);
|
||||
boolean hasError = false;
|
||||
for (ValidationMessage msg : profileErrors) {
|
||||
if (msg.getLevel()==ValidationMessage.IssueSeverity.ERROR || msg.getLevel()==ValidationMessage.IssueSeverity.FATAL) {
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasError)
|
||||
if (hasErrors(profileErrors))
|
||||
badProfiles.add(profileErrors);
|
||||
else
|
||||
goodProfiles.put(typeProfile, profileErrors);
|
||||
|
|
|
@ -101,7 +101,9 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
|
|||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
System.out.println("Name: " + name);
|
||||
String v = "5.0";
|
||||
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||
if (content.has("version"))
|
||||
v = content.get("version").getAsString();
|
||||
|
||||
|
@ -138,8 +140,9 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
|
|||
if (content.has("profiles")) {
|
||||
for (JsonElement je : content.getAsJsonArray("profiles")) {
|
||||
String p = je.getAsString();
|
||||
System.out.println("Profile: " + p);
|
||||
String filename = TestUtilities.resourceNameToFile("validation-examples", p);
|
||||
StructureDefinition sd = loadProfile(filename, v);
|
||||
StructureDefinition sd = loadProfile(filename, v, messages);
|
||||
val.getContext().cacheResource(sd);
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +157,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
|
|||
JsonObject profile = content.getAsJsonObject("profile");
|
||||
String filename = TestUtilities.resourceNameToFile("validation-examples", profile.get("source").getAsString());
|
||||
v = content.has("version") ? content.get("version").getAsString() : Constants.VERSION;
|
||||
StructureDefinition sd = loadProfile(filename, v);
|
||||
StructureDefinition sd = loadProfile(filename, v, messages);
|
||||
if (name.startsWith("Json."))
|
||||
val.validate(null, errorsProfile, new FileInputStream(path), FhirFormat.JSON, sd);
|
||||
else
|
||||
|
@ -163,14 +166,23 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
|
|||
}
|
||||
}
|
||||
|
||||
public StructureDefinition loadProfile(String filename, String v) throws IOException, FHIRFormatError, FileNotFoundException, FHIRException, DefinitionException {
|
||||
public StructureDefinition loadProfile(String filename, String v, List<ValidationMessage> messages) throws IOException, FHIRFormatError, FileNotFoundException, FHIRException, DefinitionException {
|
||||
StructureDefinition sd = (StructureDefinition) loadResource(filename, v);
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), messages, null);
|
||||
if (!sd.hasSnapshot()) {
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
|
||||
StructureDefinition base = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition());
|
||||
pu.generateSnapshot(base, sd, sd.getUrl(), null, sd.getTitle());
|
||||
// (debugging) new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", sd.getId()+".xml")), sd);
|
||||
}
|
||||
for (Resource r: sd.getContained()) {
|
||||
if (r instanceof StructureDefinition) {
|
||||
StructureDefinition childSd = (StructureDefinition)r;
|
||||
if (!childSd.hasSnapshot()) {
|
||||
StructureDefinition base = TestingUtilities.context().fetchResource(StructureDefinition.class, childSd.getBaseDefinition());
|
||||
pu.generateSnapshot(base, childSd, childSd.getUrl(), null, childSd.getTitle());
|
||||
}
|
||||
}
|
||||
}
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
|
|
@ -360,6 +360,7 @@
|
|||
]
|
||||
},
|
||||
"slice-by-polymorphic-type.xml": {
|
||||
"version": "4.0",
|
||||
"errorCount": 0,
|
||||
"profile": {
|
||||
"source": "slice-by-polymorphic-type-profile.xml",
|
||||
|
@ -411,6 +412,7 @@
|
|||
}
|
||||
},
|
||||
"slicing-types-by-string.xml": {
|
||||
"version": "4.0",
|
||||
"errorCount": 0,
|
||||
"profile": {
|
||||
"source": "slicing-types-by-string-profile.xml",
|
||||
|
@ -729,6 +731,7 @@
|
|||
"source": "patient-translated-codes.profile.xml",
|
||||
"errorCount": 0,
|
||||
"warningCount": 0
|
||||
}
|
||||
},
|
||||
"patient-contained-org.xml": {
|
||||
"errorCount": 0,
|
||||
|
@ -736,6 +739,12 @@
|
|||
"source": "patient-contained-org-profile.xml",
|
||||
"errorCount": 1
|
||||
}
|
||||
},
|
||||
"multi-profile-same-resource.xml": {
|
||||
"errorCount": 0,
|
||||
"profile": {
|
||||
"source": "multi-profile-same-resource-profile.xml",
|
||||
"errorCount": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<StructureDefinition xmlns="http://hl7.org/fhir">
|
||||
<id value="multi-profile-same-resource-profile"/>
|
||||
<contained>
|
||||
<StructureDefinition>
|
||||
<id value="pract1"/>
|
||||
<url value="http://hl7.org/fhir/StructureDefinition/multi-profile-same-resource-profile-pract1"/>
|
||||
<name value="MultiProfileSameResourceProfilePract1"/>
|
||||
<status value="draft"/>
|
||||
<kind value="resource"/>
|
||||
<abstract value="false"/>
|
||||
<type value="Practitioner"/>
|
||||
<baseDefinition value="http://hl7.org/fhir/StructureDefinition/Practitioner"/>
|
||||
<derivation value="constraint"/>
|
||||
<differential>
|
||||
<element id="Practitioner">
|
||||
<path value="Practitioner"/>
|
||||
</element>
|
||||
<element id="Practitioner.name">
|
||||
<path value="Practitioner.name"/>
|
||||
<min value="1"/>
|
||||
</element>
|
||||
<element id="Practitioner.gender">
|
||||
<path value="Practitioner.gender"/>
|
||||
<max value="0"/>
|
||||
</element>
|
||||
</differential>
|
||||
</StructureDefinition>
|
||||
</contained>
|
||||
<contained>
|
||||
<StructureDefinition>
|
||||
<id value="pract2"/>
|
||||
<url value="http://hl7.org/fhir/StructureDefinition/multi-profile-same-resource-profile-pract2"/>
|
||||
<name value="MultiProfileSameResourceProfilePract2"/>
|
||||
<status value="draft"/>
|
||||
<kind value="resource"/>
|
||||
<abstract value="false"/>
|
||||
<type value="Practitioner"/>
|
||||
<baseDefinition value="http://hl7.org/fhir/StructureDefinition/Practitioner"/>
|
||||
<derivation value="constraint"/>
|
||||
<differential>
|
||||
<element id="Practitioner">
|
||||
<path value="Practitioner"/>
|
||||
</element>
|
||||
<element id="Practitioner.name">
|
||||
<path value="Practitioner.name"/>
|
||||
<max value="0"/>
|
||||
</element>
|
||||
<element id="Practitioner.gender">
|
||||
<path value="Practitioner.gender"/>
|
||||
<min value="1"/>
|
||||
</element>
|
||||
</differential>
|
||||
</StructureDefinition>
|
||||
</contained>
|
||||
<url value="http://hl7.org/fhir/StructureDefinition/multi-profile-same-resource-profile"/>
|
||||
<name value="MultiProfileSameResourceProfile"/>
|
||||
<status value="draft"/>
|
||||
<description value="Profile with multiple profiles allowed for teh same resource"/>
|
||||
<kind value="resource"/>
|
||||
<abstract value="false"/>
|
||||
<type value="Patient"/>
|
||||
<baseDefinition value="http://hl7.org/fhir/StructureDefinition/Patient"/>
|
||||
<derivation value="constraint"/>
|
||||
<differential>
|
||||
<element id="Patient">
|
||||
<path value="Patient"/>
|
||||
</element>
|
||||
<element id="Patient.generalPractitioner">
|
||||
<path value="Patient.generalPractitioner"/>
|
||||
<min value="1"/>
|
||||
<max value="1"/>
|
||||
<type>
|
||||
<code value="Reference"/>
|
||||
<targetProfile value="#pract1"/>
|
||||
<targetProfile value="#pract2"/>
|
||||
</type>
|
||||
</element>
|
||||
</differential>
|
||||
</StructureDefinition>
|
|
@ -0,0 +1,17 @@
|
|||
<Patient xmlns="http://hl7.org/fhir">
|
||||
<id value="multi-profile-same-resource"/>
|
||||
<text>
|
||||
<status value="generated"/>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
</div>
|
||||
</text>
|
||||
<contained>
|
||||
<Practitioner>
|
||||
<id value="practitioner"/>
|
||||
<gender value="other"/>
|
||||
</Practitioner>
|
||||
</contained>
|
||||
<generalPractitioner>
|
||||
<reference value="#practitioner"/>
|
||||
</generalPractitioner>
|
||||
</Patient>
|
|
@ -2,7 +2,7 @@
|
|||
"resourceType": "Encounter",
|
||||
"id": "f003",
|
||||
"class" : {
|
||||
"system" : "http://hl7.org/fhir/v3/ActCode",
|
||||
"system" : "http://terminology.hl7.org/CodeSystem/v3-ActCode",
|
||||
"code" : "AMB"
|
||||
},
|
||||
"text": {
|
||||
|
@ -22,7 +22,7 @@
|
|||
"reference": "Patient/f001",
|
||||
"display": "P. van de Heuvel"
|
||||
},
|
||||
"reason": {
|
||||
"reasonCode": {
|
||||
"extension": [
|
||||
{
|
||||
"url": "http://hl7.org/fhir/StructureDefinition/iso21090-nullFlavor",
|
||||
|
|
Loading…
Reference in New Issue