Merge pull request #1569 from hapifhir/2024-02-gg-pat-cont-resources

2024 02 gg pat cont resources
This commit is contained in:
Grahame Grieve 2024-02-28 13:34:19 +11:00 committed by GitHub
commit d5de8052f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 83 additions and 265 deletions

View File

@ -18,6 +18,7 @@
* Fix where validator was ignoring minimum cardinality for XML attributes (especially in CDA) * Fix where validator was ignoring minimum cardinality for XML attributes (especially in CDA)
* Improved ConceptMap validation * Improved ConceptMap validation
* Updated IG versions used for -cda and -ccda CLI validation options. * Updated IG versions used for -cda and -ccda CLI validation options.
* Change validator so that it marks value properties in primitive data types as illegal
## Other code changes ## Other code changes
@ -32,3 +33,8 @@
* Fix wrong URLs rendering Profiles and Questionnaires * Fix wrong URLs rendering Profiles and Questionnaires
* Fix bug using wrong version constant for R3 * Fix bug using wrong version constant for R3
* Updates for R5 StructureMap syntax * Updates for R5 StructureMap syntax
* Support for case sensitive Code system tests
* Add TurtleGeneratorTests for R5
* Introduce new validator cliContext option disableDefaultResourceFetcher (#1526)
* Render contained resources when rendering Patient resources
* Fix bug in FML Parser

View File

@ -66,14 +66,14 @@ class Convertor_Factory_40_50Test {
StructureMapUtilities smu5 = new StructureMapUtilities(context, mock(org.hl7.fhir.r5.utils.structuremap.ITransformerServices.class)); StructureMapUtilities smu5 = new StructureMapUtilities(context, mock(org.hl7.fhir.r5.utils.structuremap.ITransformerServices.class));
org.hl7.fhir.r5.model.StructureMap mapR5 = smu5.parse(CONTENT, "map"); org.hl7.fhir.r5.model.StructureMap mapR5 = smu5.parse(CONTENT, "map");
assertEquals("tgt", mapR5.getGroup().get(0).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueIdType().getValue()); assertEquals("tgt", mapR5.getGroup().get(0).getRule().get(0).getTarget().get(0).getContext());
assertEquals("item.answer.valueString", mapR5.getGroup().get(1).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueStringType().getValue()); assertEquals("item.answer.valueString", mapR5.getGroup().get(1).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueStringType().getValue());
assertEquals("item", mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(0).getValueIdType().getValueAsString()); assertEquals("item", mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(0).getValueIdType().getValueAsString());
assertEquals("patient", mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(1).getValueIdType().getValueAsString()); assertEquals("patient", mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(1).getValueIdType().getValueAsString());
org.hl7.fhir.r4.model.StructureMap mapR4 = (org.hl7.fhir.r4.model.StructureMap) VersionConvertorFactory_40_50.convertResource(mapR5); org.hl7.fhir.r4.model.StructureMap mapR4 = (org.hl7.fhir.r4.model.StructureMap) VersionConvertorFactory_40_50.convertResource(mapR5);
assertEquals("tgt", mapR4.getGroup().get(0).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueIdType().getValue()); assertEquals("tgt", mapR4.getGroup().get(0).getRule().get(0).getTarget().get(0).getContext());
assertEquals("item.answer.valueString", mapR4.getGroup().get(1).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueStringType().getValue()); assertEquals("item.answer.valueString", mapR4.getGroup().get(1).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueStringType().getValue());
assertEquals("item", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(0).getValueAsString()); assertEquals("item", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(0).getValueAsString());
assertEquals("patient", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(1).getValueAsString()); assertEquals("patient", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(1).getValueAsString());
@ -87,7 +87,7 @@ class Convertor_Factory_40_50Test {
StructureMap mapR5Back = (StructureMap) VersionConvertorFactory_40_50.convertResource(mapR4); StructureMap mapR5Back = (StructureMap) VersionConvertorFactory_40_50.convertResource(mapR4);
assertEquals("tgt", mapR5Back.getGroup().get(0).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueIdType().getValue()); assertEquals("tgt", mapR5Back.getGroup().get(0).getRule().get(0).getTarget().get(0).getContext());
assertEquals("item.answer.valueString", mapR5Back.getGroup().get(1).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueStringType().getValue()); assertEquals("item.answer.valueString", mapR5Back.getGroup().get(1).getRule().get(0).getTarget().get(0).getParameter().get(0).getValueStringType().getValue());
assertEquals("item", mapR5Back.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(0).getValueIdType().getValueAsString()); assertEquals("item", mapR5Back.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(0).getValueIdType().getValueAsString());
assertEquals("patient", mapR5Back.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(1).getValueIdType().getValueAsString()); assertEquals("patient", mapR5Back.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(1).getValueIdType().getValueAsString());

View File

@ -32,6 +32,7 @@ import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper; import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlNode;
@ -269,7 +270,7 @@ public class PatientRenderer extends ResourceRenderer {
} }
@Override @Override
public boolean render(XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException { public boolean render(XhtmlNode x, ResourceWrapper r) throws IOException, FHIRException, EOperationOutcome {
// banner // banner
describe(makeBanner(x.para()), r); describe(makeBanner(x.para()), r);
x.hr(); x.hr();
@ -295,9 +296,22 @@ public class PatientRenderer extends ResourceRenderer {
if (tbl.isEmpty()) { if (tbl.isEmpty()) {
x.remove(tbl); x.remove(tbl);
} }
if (r.has("contained") && context.isTechnicalMode()) {
x.hr();
x.para().b().tx("Contained Resources");
addContained(x, r.getContained());
}
return false; return false;
} }
private void addContained(XhtmlNode x, List<ResourceWrapper> list) throws FHIRFormatError, DefinitionException, FHIRException, IOException, EOperationOutcome {
for (ResourceWrapper c : list) {
x.hr();
x.an(c.getId());
new RendererFactory().factory(c, context).render(x, c);
}
}
private void addExtensions(XhtmlNode tbl, ResourceWrapper r) throws UnsupportedEncodingException, FHIRException, IOException { private void addExtensions(XhtmlNode tbl, ResourceWrapper r) throws UnsupportedEncodingException, FHIRException, IOException {
Map<String, List<Extension>> extensions = new HashMap<>(); Map<String, List<Extension>> extensions = new HashMap<>();
PropertyWrapper pw = getProperty(r, "extension"); PropertyWrapper pw = getProperty(r, "extension");

View File

@ -1141,6 +1141,7 @@ public class StructureMapUtilities {
} }
lexer.token(")"); lexer.token(")");
} else if (name != null) { } else if (name != null) {
if (target.getContext() != null) {
target.setTransform(StructureMapTransform.COPY); target.setTransform(StructureMapTransform.COPY);
if (!isConstant) { if (!isConstant) {
String id = name; String id = name;
@ -1150,6 +1151,9 @@ public class StructureMapUtilities {
target.addParameter().setValue(new IdType(id)); target.addParameter().setValue(new IdType(id));
} else } else
target.addParameter().setValue(readConstant(name, lexer)); target.addParameter().setValue(readConstant(name, lexer));
} else {
target.setContext(name);
}
} }
if (lexer.hasToken("as")) { if (lexer.hasToken("as")) {
lexer.take(); lexer.take();
@ -1716,10 +1720,9 @@ public class StructureMapUtilities {
Base dest = null; Base dest = null;
if (tgt.hasContext()) { if (tgt.hasContext()) {
dest = vars.get(VariableMode.OUTPUT, tgt.getContext()); dest = vars.get(VariableMode.OUTPUT, tgt.getContext());
if (dest == null) if (dest == null) {
throw new FHIRException("Rule \"" + rulePath + "\": target context not known: " + tgt.getContext()); throw new FHIRException("Rul \"" + rulePath + "\": target context not known: " + tgt.getContext());
if (!tgt.hasElement()) }
throw new FHIRException("Rule \"" + rulePath + "\": Not supported yet");
} }
Base v = null; Base v = null;
if (tgt.hasTransform()) { if (tgt.hasTransform()) {
@ -1738,8 +1741,10 @@ public class StructureMapUtilities {
v = dest.makeProperty(tgt.getElement().hashCode(), tgt.getElement()); v = dest.makeProperty(tgt.getElement().hashCode(), tgt.getElement());
sharedVars.add(VariableMode.SHARED, tgt.getListRuleId(), v); sharedVars.add(VariableMode.SHARED, tgt.getListRuleId(), v);
} }
} else { } else if (tgt.hasElement()) {
v = dest.makeProperty(tgt.getElement().hashCode(), tgt.getElement()); v = dest.makeProperty(tgt.getElement().hashCode(), tgt.getElement());
} else {
v = dest;
} }
} }
if (tgt.hasVariable() && v != null) if (tgt.hasVariable() && v != null)

View File

@ -703,7 +703,11 @@ public class VersionUtilities {
} }
public static String getNameForVersion(String v) { public static String getNameForVersion(String v) {
switch (getMajMin(v)) { String mm = getMajMin(v);
if (mm == null) {
throw new Error("Unable to determine version for '"+v+"'");
}
switch (mm) {
case "1.0" : return "R2"; case "1.0" : return "R2";
case "1.4" : return "R2B"; case "1.4" : return "R2B";
case "3.0" : return "R3"; case "3.0" : return "R3";

View File

@ -1059,6 +1059,7 @@ public class I18nConstants {
public static final String VALUESET_INCLUDE_CSVER_MULTI_FOUND = "VALUESET_INCLUDE_CSVER_MULTI_FOUND"; public static final String VALUESET_INCLUDE_CSVER_MULTI_FOUND = "VALUESET_INCLUDE_CSVER_MULTI_FOUND";
public static final String UNABLE_TO_INFER_CODESYSTEM = "UNABLE_TO_INFER_CODESYSTEM"; public static final String UNABLE_TO_INFER_CODESYSTEM = "UNABLE_TO_INFER_CODESYSTEM";
public static final String CODE_CASE_DIFFERENCE = "CODE_CASE_DIFFERENCE"; public static final String CODE_CASE_DIFFERENCE = "CODE_CASE_DIFFERENCE";
public static final String ILLEGAL_PROPERTY = "ILLEGAL_PROPERTY";
} }

View File

@ -1117,3 +1117,4 @@ VALUESET_INCLUDE_CS_MULTI_FOUND = Multiple matching contained code systems found
VALUESET_INCLUDE_CSVER_MULTI_FOUND = Multiple matching contained code systems found for system ''{0}'' version ''{1}'' VALUESET_INCLUDE_CSVER_MULTI_FOUND = Multiple matching contained code systems found for system ''{0}'' version ''{1}''
CODE_CASE_DIFFERENCE = The code ''{0}'' differs from the correct code ''{1}'' by case. Although the code system ''{2}'' is case insensitive, implementers are strongly encouraged to use the correct case anyway CODE_CASE_DIFFERENCE = The code ''{0}'' differs from the correct code ''{1}'' by case. Although the code system ''{2}'' is case insensitive, implementers are strongly encouraged to use the correct case anyway
SCT_NO_MRCM = Not validated against the Machine Readable Concept Model (MRCM) SCT_NO_MRCM = Not validated against the Machine Readable Concept Model (MRCM)
ILLEGAL_PROPERTY = The property ''{0}'' is invalid

View File

@ -2627,6 +2627,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean checkPrimitive(ValidationContext valContext, List<ValidationMessage> errors, String path, String type, ElementDefinition context, Element e, StructureDefinition profile, NodeStack node, NodeStack parentNode, Element resource) throws FHIRException { private boolean checkPrimitive(ValidationContext valContext, List<ValidationMessage> errors, String path, String type, ElementDefinition context, Element e, StructureDefinition profile, NodeStack node, NodeStack parentNode, Element resource) throws FHIRException {
boolean ok = true; boolean ok = true;
// sanity check. The only children allowed are id and extension, but value might slip through in some circumstances.
for (Element child : e.getChildren()) {
ok = rule(errors, "2024-02-28", IssueType.INVALID, child.line(), child.col(), path, !"value".equals(child.getName()), I18nConstants.ILLEGAL_PROPERTY, "value") && ok;
}
if (isBlank(e.primitiveValue())) { if (isBlank(e.primitiveValue())) {
if (e.primitiveValue() == null) if (e.primitiveValue() == null)
ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.hasChildren(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_VALUEEXT) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.INVALID, e.line(), e.col(), path, e.hasChildren(), I18nConstants.TYPE_SPECIFIC_CHECKS_DT_PRIMITIVE_VALUEEXT) && ok;
@ -6116,7 +6122,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
childDefinitions = getActualTypeChildren(valContext, element, actualType); childDefinitions = getActualTypeChildren(valContext, element, actualType);
} else if (definition.getType().size() > 1) { } else if (definition.getType().size() > 1) {
// this only happens when the profile constrains the abstract children but leaves th choice open. // this only happens when the profile constrains the abstract children but leaves the choice open.
if (actualType == null) { if (actualType == null) {
vi.setValid(false); vi.setValid(false);
return false; // there'll be an error elsewhere in this case, and we're going to stop. return false; // there'll be an error elsewhere in this case, and we're going to stop.

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.r5.test; package org.hl7.fhir.validation.tests;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;

View File

@ -20,7 +20,7 @@
<properties> <properties>
<guava_version>32.0.1-jre</guava_version> <guava_version>32.0.1-jre</guava_version>
<hapi_fhir_version>6.4.1</hapi_fhir_version> <hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.4.29-SNAPSHOT</validator_test_case_version> <validator_test_case_version>1.5.0-SNAPSHOT</validator_test_case_version>
<jackson_version>2.16.0</jackson_version> <jackson_version>2.16.0</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version> <junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version> <junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>