diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index 1a3abd041..5126e13c0 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -2150,6 +2150,14 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte } } + @Override + public List fetchTypeDefinitions(String typeName) { + List res = new ArrayList<>(); + structures.listAll(res); + res.removeIf(sd -> !sd.getType().equals(typeName)); + return res; + } + public boolean isTlogging() { return tlogging; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java index cd26fab61..2ec1b9b7f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/IWorkerContext.java @@ -3,6 +3,7 @@ package org.hl7.fhir.r5.context; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import java.util.Date; /* @@ -736,13 +737,21 @@ public interface IWorkerContext { /** * This is a short cut for fetchResource(StructureDefinition.class, ...) * but it accepts a typename - that is, it resolves based on StructureDefinition.type - * or StructureDefinition.url + * or StructureDefinition.url. This only resolves to http://hl7.org/fhir/StructureDefinition/{typename} * * @param typeName * @return */ public StructureDefinition fetchTypeDefinition(String typeName); + /** + * This finds all the structure definitions that have the given typeName + * + * @param typeName + * @return + */ + public List fetchTypeDefinitions(String n); + /** * Returns a set of keys that can be used to get binaries from this context. diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/OperationOutcome.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/OperationOutcome.java index bdbe8a9ab..d6466c881 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/OperationOutcome.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/OperationOutcome.java @@ -1340,6 +1340,29 @@ public String toString() { return getExpression()+" "+getDiagnostics()+" "+getSeverity().toCode()+"/"+getCode().toCode()+": "+getDetails().getText(); } } + +public boolean isWarningOrMore() { + switch (getSeverity()) { + case FATAL: return true; + case ERROR: return true; + case WARNING: return true; + case INFORMATION: return false; + case SUCCESS: return false; + case NULL: return false; + default: return false; +} +} +public boolean isInformationorLess() { + switch (getSeverity()) { + case FATAL: return false; + case ERROR: return true; + case WARNING: return false; + case INFORMATION: return true; + case SUCCESS: return true; + case NULL: return true; + default: return false; +} +} // end addition } @@ -1543,6 +1566,19 @@ public String toString() { return ResourceType.OperationOutcome; } + + public boolean isSuccess() { + for (OperationOutcomeIssueComponent iss : getIssue()) { + if (iss.isWarningOrMore() || iss.getCode() != IssueType.INFORMATIONAL) { + return false; + } + if (iss.isInformationorLess() || iss.getCode() != IssueType.INFORMATIONAL) { + return true; + } + } + return false; + } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/TypeDetails.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/TypeDetails.java index 2a4667bcb..1c748d2dc 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/TypeDetails.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/TypeDetails.java @@ -229,22 +229,34 @@ public class TypeDetails { tail = n.substring( n.indexOf("#")+1); tail = tail.substring(tail.indexOf(".")); } - String t = ProfiledType.ns(n); - StructureDefinition sd = context.fetchResource(StructureDefinition.class, t); - while (sd != null) { - if (tail == null && typesContains(sd.getUrl())) - return true; - if (tail == null && getSystemType(sd.getUrl()) != null && typesContains(getSystemType(sd.getUrl()))) - return true; - if (tail != null && typesContains(sd.getUrl()+"#"+sd.getType()+tail)) - return true; - if (sd.hasBaseDefinition()) { - if (sd.getType().equals("uri")) - sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/string"); - else - sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); - } else - sd = null; + List list = new ArrayList<>(); + if (!Utilities.isAbsoluteUrl(n)) { + list.addAll(context.fetchTypeDefinitions(n)); + } else { + String t = ProfiledType.ns(n); + StructureDefinition sd = context.fetchResource(StructureDefinition.class, t); + if (sd != null) { + list.add(sd); + } + } + for (int i = 0; i < list.size(); i++) { + StructureDefinition sd = list.get(i); + while (sd != null) { + if (tail == null && typesContains(sd.getUrl())) + return true; + if (tail == null && getSystemType(sd.getUrl()) != null && typesContains(getSystemType(sd.getUrl()))) + return true; + if (tail != null && typesContains(sd.getUrl()+"#"+sd.getType()+tail)) + return true; + if (sd.hasBaseDefinition()) { + if (sd.getType().equals("uri")) + sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/string"); + else + sd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); + } else { + sd = null; + } + } } } return false; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index 7dd086979..3ef9b1634 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -6045,7 +6045,12 @@ public class FHIRPathEngine { } private boolean isAbstractType(List list) { - return list.size() != 1 ? true : Utilities.existsInList(list.get(0).getCode(), "Element", "BackboneElement", "Resource", "DomainResource"); + if (list.size() != 1) { + return false; + } else { + StructureDefinition sd = worker.fetchTypeDefinition(list.get(0).getCode()); + return sd != null && sd.getAbstract(); + } } private boolean hasType(ElementDefinition ed, String s) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/ResolvedGroup.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/ResolvedGroup.java index f10ff85ea..96b5fe539 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/ResolvedGroup.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/ResolvedGroup.java @@ -1,8 +1,32 @@ package org.hl7.fhir.r5.utils.structuremap; import org.hl7.fhir.r5.model.StructureMap; +import org.hl7.fhir.r5.model.StructureMap.StructureMapGroupComponent; public class ResolvedGroup { - public StructureMap.StructureMapGroupComponent target; - public StructureMap targetMap; + private StructureMap.StructureMapGroupComponent targetGroup; + private StructureMap targetMap; + + public ResolvedGroup(StructureMap targetMap, StructureMapGroupComponent targetGroup) { + super(); + this.targetMap = targetMap; + this.targetGroup = targetGroup; + } + + public StructureMap.StructureMapGroupComponent getTargetGroup() { + return targetGroup; + } + public StructureMap getTargetMap() { + return targetMap; + } + + public void setTargetGroup(StructureMap.StructureMapGroupComponent targetGroup) { + this.targetGroup = targetGroup; + } + + public void setTargetMap(StructureMap targetMap) { + this.targetMap = targetMap; + } + + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java index 63f5a3d6c..7936e305a 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/structuremap/StructureMapUtilities.java @@ -1243,7 +1243,7 @@ public class StructureMapUtilities { // todo: check inputs if (group.hasExtends()) { ResolvedGroup rg = resolveGroupReference(map, group, group.getExtends()); - executeGroup(indent + " ", context, rg.targetMap, vars, rg.target, false); + executeGroup(indent + " ", context, rg.getTargetMap(), vars, rg.getTargetGroup(), false); } for (StructureMapGroupRuleComponent r : group.getRule()) { @@ -1279,9 +1279,9 @@ public class StructureMapUtilities { String tgtType = tgt.fhirType(); ResolvedGroup defGroup = resolveGroupByTypes(map, rule.getName(), group, srcType, tgtType); Variables vdef = new Variables(); - vdef.add(VariableMode.INPUT, defGroup.target.getInput().get(0).getName(), src); - vdef.add(VariableMode.OUTPUT, defGroup.target.getInput().get(1).getName(), tgt); - executeGroup(indent + " ", context, defGroup.targetMap, vdef, defGroup.target, false); + vdef.add(VariableMode.INPUT, defGroup.getTargetGroup().getInput().get(0).getName(), src); + vdef.add(VariableMode.OUTPUT, defGroup.getTargetGroup().getInput().get(1).getName(), tgt); + executeGroup(indent + " ", context, defGroup.getTargetMap(), vdef, defGroup.getTargetGroup(), false); } } } @@ -1290,12 +1290,12 @@ public class StructureMapUtilities { private void executeDependency(String indent, TransformContext context, StructureMap map, Variables vin, StructureMapGroupComponent group, StructureMapGroupRuleDependentComponent dependent) throws FHIRException { ResolvedGroup rg = resolveGroupReference(map, group, dependent.getName()); - if (rg.target.getInput().size() != dependent.getParameter().size()) { - throw new FHIRException("Rule '" + dependent.getName() + "' has " + rg.target.getInput().size() + " but the invocation has " + dependent.getParameter().size() + " variables"); + if (rg.getTargetGroup().getInput().size() != dependent.getParameter().size()) { + throw new FHIRException("Rule '" + dependent.getName() + "' has " + rg.getTargetGroup().getInput().size() + " but the invocation has " + dependent.getParameter().size() + " variables"); } Variables v = new Variables(); - for (int i = 0; i < rg.target.getInput().size(); i++) { - StructureMapGroupInputComponent input = rg.target.getInput().get(i); + for (int i = 0; i < rg.getTargetGroup().getInput().size(); i++) { + StructureMapGroupInputComponent input = rg.getTargetGroup().getInput().get(i); StructureMapGroupRuleTargetParameterComponent rdp = dependent.getParameter().get(i); String var = rdp.getValue().primitiveValue(); VariableMode mode = input.getMode() == StructureMapInputMode.SOURCE ? VariableMode.INPUT : VariableMode.OUTPUT; @@ -1306,7 +1306,7 @@ public class StructureMapUtilities { throw new FHIRException("Rule '" + dependent.getName() + "' " + mode.toString() + " variable '" + input.getName() + "' named as '" + var + "' has no value (vars = " + vin.summary() + ")"); v.add(mode, input.getName(), vv); } - executeGroup(indent + " ", context, rg.targetMap, v, rg.target, false); + executeGroup(indent + " ", context, rg.getTargetMap(), v, rg.getTargetGroup(), false); } private String determineTypeFromSourceType(StructureMap map, StructureMapGroupComponent source, Base base, String[] types) throws FHIRException { @@ -1315,20 +1315,18 @@ public class StructureMapUtilities { if (source.hasUserData(kn)) return source.getUserString(kn); - ResolvedGroup res = new ResolvedGroup(); - res.targetMap = null; - res.target = null; + ResolvedGroup res = new ResolvedGroup(null, null); for (StructureMapGroupComponent grp : map.getGroup()) { if (matchesByType(map, grp, type)) { - if (res.targetMap == null) { - res.targetMap = map; - res.target = grp; + if (res.getTargetMap() == null) { + res.setTargetMap(map); + res.setTargetGroup(grp); } else throw new FHIRException("Multiple possible matches looking for default rule for '" + type + "'"); } } - if (res.targetMap != null) { - String result = getActualType(res.targetMap, res.target.getInput().get(1).getType()); + if (res.getTargetMap() != null) { + String result = getActualType(res.getTargetMap(), res.getTargetGroup().getInput().get(1).getType()); source.setUserData(kn, result); return result; } @@ -1341,19 +1339,19 @@ public class StructureMapUtilities { if (!impMap.getUrl().equals(map.getUrl())) { for (StructureMapGroupComponent grp : impMap.getGroup()) { if (matchesByType(impMap, grp, type)) { - if (res.targetMap == null) { - res.targetMap = impMap; - res.target = grp; + if (res.getTargetMap() == null) { + res.setTargetMap(impMap); + res.setTargetGroup(grp); } else - throw new FHIRException("Multiple possible matches for default rule for '" + type + "' in " + res.targetMap.getUrl() + " (" + res.target.getName() + ") and " + impMap.getUrl() + " (" + grp.getName() + ")"); + throw new FHIRException("Multiple possible matches for default rule for '" + type + "' in " + res.getTargetMap().getUrl() + " (" + res.getTargetGroup().getName() + ") and " + impMap.getUrl() + " (" + grp.getName() + ")"); } } } } } - if (res.target == null) + if (res.getTargetGroup() == null) throw new FHIRException("No matches found for default rule for '" + type + "' from " + map.getUrl()); - String result = getActualType(res.targetMap, res.target.getInput().get(1).getType()); // should be .getType, but R2... + String result = getActualType(res.getTargetMap(), res.getTargetGroup().getInput().get(1).getType()); // should be .getType, but R2... source.setUserData(kn, result); return result; } @@ -1390,19 +1388,17 @@ public class StructureMapUtilities { if (source.hasUserData(kn)) return (ResolvedGroup) source.getUserData(kn); - ResolvedGroup res = new ResolvedGroup(); - res.targetMap = null; - res.target = null; + ResolvedGroup res = new ResolvedGroup(null, null); for (StructureMapGroupComponent grp : map.getGroup()) { if (matchesByType(map, grp, srcType, tgtType)) { - if (res.targetMap == null) { - res.targetMap = map; - res.target = grp; + if (res.getTargetMap() == null) { + res.setTargetMap(map); + res.setTargetGroup(grp); } else throw new FHIRException("Multiple possible matches looking for rule for '" + srcType + "/" + tgtType + "', from rule '" + ruleid + "'"); } } - if (res.targetMap != null) { + if (res.getTargetMap() != null) { source.setUserData(kn, res); return res; } @@ -1415,17 +1411,17 @@ public class StructureMapUtilities { if (!impMap.getUrl().equals(map.getUrl())) { for (StructureMapGroupComponent grp : impMap.getGroup()) { if (matchesByType(impMap, grp, srcType, tgtType)) { - if (res.targetMap == null) { - res.targetMap = impMap; - res.target = grp; + if (res.getTargetMap() == null) { + res.setTargetMap(impMap); + res.setTargetGroup(grp); } else - throw new FHIRException("Multiple possible matches for rule for '" + srcType + "/" + tgtType + "' in " + res.targetMap.getUrl() + " and " + impMap.getUrl() + ", from rule '" + ruleid + "'"); + throw new FHIRException("Multiple possible matches for rule for '" + srcType + "/" + tgtType + "' in " + res.getTargetMap().getUrl() + " and " + impMap.getUrl() + ", from rule '" + ruleid + "'"); } } } } } - if (res.target == null) + if (res.getTargetGroup() == null) throw new FHIRException("No matches found for rule for '" + srcType + " to " + tgtType + "' from " + map.getUrl() + ", from rule '" + ruleid + "'"); source.setUserData(kn, res); return res; @@ -1493,19 +1489,17 @@ public class StructureMapUtilities { if (source.hasUserData(kn)) return (ResolvedGroup) source.getUserData(kn); - ResolvedGroup res = new ResolvedGroup(); - res.targetMap = null; - res.target = null; + ResolvedGroup res = new ResolvedGroup(null, null); for (StructureMapGroupComponent grp : map.getGroup()) { if (grp.getName().equals(name)) { - if (res.targetMap == null) { - res.targetMap = map; - res.target = grp; + if (res.getTargetMap() == null) { + res.setTargetMap(map); + res.setTargetGroup(grp); } else throw new FHIRException("Multiple possible matches for rule '" + name + "'"); } } - if (res.targetMap != null) { + if (res.getTargetMap() != null) { source.setUserData(kn, res); return res; } @@ -1518,19 +1512,19 @@ public class StructureMapUtilities { if (!impMap.getUrl().equals(map.getUrl())) { for (StructureMapGroupComponent grp : impMap.getGroup()) { if (grp.getName().equals(name)) { - if (res.targetMap == null) { - res.targetMap = impMap; - res.target = grp; + if (res.getTargetMap() == null) { + res.setTargetMap(impMap); + res.setTargetGroup(grp); } else throw new FHIRException("Multiple possible matches for rule group '" + name + "' in " + - res.targetMap.getUrl() + "#" + res.target.getName() + " and " + + res.getTargetMap().getUrl() + "#" + res.getTargetGroup().getName() + " and " + impMap.getUrl() + "#" + grp.getName()); } } } } } - if (res.target == null) + if (res.getTargetGroup() == null) throw new FHIRException("No matches found for rule '" + name + "'. Reference found in " + map.getUrl()); source.setUserData(kn, res); return res; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index 699bade3a..f7edb9692 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -846,6 +846,7 @@ public class I18nConstants { public static final String CONCEPTMAP_GROUP_TARGET_PROPERTY_TYPE_NO_SYSTEM = "CONCEPTMAP_GROUP_TARGET_PROPERTY_TYPE_NO_SYSTEM"; public static final String CONCEPTMAP_GROUP_TARGET_PROPERTY_CODE_INVALID = "CONCEPTMAP_GROUP_TARGET_PROPERTY_CODE_INVALID"; public static final String CONCEPTMAP_GROUP_TARGET_PROPERTY_TYPE_UNKNOWN_SYSTEM = "CONCEPTMAP_GROUP_TARGET_PROPERTY_TYPE_UNKNOWN_SYSTEM"; + public static final String SM_GROUP_NAME_DUPLICATE = "SM_GROUP_NAME_DUPLICATE"; } diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 901be98f7..e1cfde421 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -577,7 +577,7 @@ FHIRPATH_LOCATION = (at {0}) FHIRPATH_UNKNOWN_CONTEXT = Unknown context evaluating FHIRPath expression: {0} FHIRPATH_UNKNOWN_CONTEXT_ELEMENT = Unknown context element evaluating FHIRPath expression: {0} FHIRPATH_ALIAS_COLLECTION = Attempt to alias a collection, not a singleton evaluating FHIRPath expression -FHIRPATH_UNKNOWN_NAME = Error evaluating FHIRPath expression: The name {0} is not valid for any of the possible types: {1} +FHIRPATH_UNKNOWN_NAME = Error evaluating FHIRPath expression: The name ''{0}'' is not valid for any of the possible types: {1} FHIRPATH_UNKNOWN_CONSTANT = Error evaluating FHIRPath expression: Invalid FHIR Constant {0} FHIRPATH_CANNOT_USE = Error evaluating FHIRPath expression: Cannot use {0} in this context because {1} FHIRPATH_CANT_COMPARE = Error evaluating FHIRPath expression: Unable to compare values of type {0} and {1} @@ -834,6 +834,7 @@ SD_NO_SLICING_ON_ROOT = Slicing is not allowed at the root of a profile REFERENCE_REF_QUERY_INVALID = The query part of the conditional reference is not a valid query string ({0}) SM_RULEGROUP_NOT_FOUND = The group {0} could not be resolved SM_NAME_INVALID = The name {0} is not valid +SM_GROUP_NAME_DUPLICATE = The Group name ''{0}'' is already used SM_GROUP_INPUT_DUPLICATE = The name {0} is already used SM_GROUP_INPUT_MODE_INVALID = The group parameter {0} mode {1} isn''t valid SM_GROUP_INPUT_NO_TYPE = The group parameter {0} has no type, so the paths cannot be validated @@ -846,7 +847,7 @@ SM_SOURCE_PATH_INVALID = The source path {0}.{1} refers to the path {2} which is SM_RULE_SOURCE_MIN_REDUNDANT = The min value of {0} is redundant since the valid min is {0} SM_RULE_SOURCE_MAX_REDUNDANT = The max value of {0} is redundant since the valid max is {0} SM_RULE_SOURCE_LISTMODE_REDUNDANT = The listMode value of {0} is redundant since the valid max is {0} -SM_TARGET_CONTEXT_UNKNOWN = The target context {0} is not known at this point +SM_TARGET_CONTEXT_UNKNOWN = The target context ''{0}'' is not known at this point SM_TARGET_PATH_INVALID = The target path {0}.{1} refers to the path {2} which is unknown SM_NO_LIST_MODE_NEEDED = A list mode should not be provided since this is a rule that can only be executed once SM_NO_LIST_RULE_ID_NEEDED = A list ruleId should not be provided since this is a rule that can only be executed once @@ -864,7 +865,7 @@ SM_TARGET_TRANSFORM_EXPRESSION_ERROR = The FHIRPath expression passed as the eva SM_IMPORT_NOT_FOUND = No maps were found to match {0} - validation may be wrong SM_TARGET_TYPE_MULTIPLE_POSSIBLE = Multiple types are possible here ({0}) so further type checking is not possible SM_DEPENDENT_PARAM_MODE_MISMATCH = The parameter {0} refers to the variable {1} but it''s mode is {2} which is not the same as the mode required for the group {3} -SM_DEPENDENT_PARAM_TYPE_MISMATCH = The parameter {0} refers to the variable {1} but it''s type is {2} which is not compatible with the type required for the group {3} +SM_DEPENDENT_PARAM_TYPE_MISMATCH = The parameter ''{0}'' refers to the variable ''{1}'' but it''s type is ''{2}'' which is not compatible with the type required for the group ''{3}'', which is ''{4}'' (from map ''{5}'') SM_ORPHAN_GROUP = The group {0} is not called from within this mapping script, and does not have types on it's inputs, so type verification is not possible SM_SOURCE_TYPE_NOT_FOUND = No source type was found, so the default group for this implied dependent rule could not be determined SM_TARGET_TYPE_NOT_FOUND = No target type was found, so the default group for this implied dependent rule could not be determined diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/CompactRenderer.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/CompactRenderer.java index f15143afd..178cc1796 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/CompactRenderer.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/renderers/CompactRenderer.java @@ -26,17 +26,29 @@ public class CompactRenderer extends ValidationOutputRenderer { @Override public void render(OperationOutcome op) throws IOException { if (split) { - String file = Utilities.changeFileExt(tail(ToolingExtensions.readStringExtension(op, ToolingExtensions.EXT_OO_FILE)), ".txt"); - PrintStream dstF = new PrintStream(new FileOutputStream(Utilities.path(dir.getAbsolutePath(), file))); - render(dstF, op); - dstF.close(); + File file = new File(Utilities.path(dir.getAbsolutePath(), Utilities.changeFileExt(tail(ToolingExtensions.readStringExtension(op, ToolingExtensions.EXT_OO_FILE)), ".txt"))); + if (op.isSuccess()) { + if (file.exists()) { + file.delete(); + } + } else { + PrintStream dstF = new PrintStream(new FileOutputStream(file)); + render(dstF, op); + dstF.close(); + } } else { render(dst, op); } } private void render(PrintStream d, OperationOutcome op) { - d.println(ToolingExtensions.readStringExtension(op, ToolingExtensions.EXT_OO_FILE)+" "+getRunDate()); + if (split) { + d.println(new File(ToolingExtensions.readStringExtension(op, ToolingExtensions.EXT_OO_FILE)).getName()+" "+getRunDate()+":"); + } else { + d.println(); + d.println("----------------------------------------------------------------------------------"); + d.println(ToolingExtensions.readStringExtension(op, ToolingExtensions.EXT_OO_FILE)+" "+getRunDate()); + } List lines = new ArrayList<>(); for (OperationOutcome.OperationOutcomeIssueComponent issue : op.getIssue()) { String path = issue.hasExpression() ? issue.getExpression().get(0).asStringValue() : "n/a"; @@ -48,6 +60,10 @@ public class CompactRenderer extends ValidationOutputRenderer { for (String s : lines) { d.println(s.substring(s.indexOf("|")+1)); } + if (split) { + } else { + d.println(); + } } private String tail(String n) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java index 720702bbf..602467b63 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/StructureMapValidator.java @@ -33,6 +33,7 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.ValueSetUtilities; import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup; import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; @@ -173,6 +174,8 @@ public class StructureMapValidator extends BaseValidator { if (ed != null) { if (!ed.getPath().contains(".")) { return ed.getPath(); + } else if (isAbstractType(ed.getType())) { + return sd.getUrl()+"#"+ed.getPath(); } else if (ed.getType().size() == 1) { return ed.getType().get(0).getWorkingCode(); } @@ -305,6 +308,16 @@ public class StructureMapValidator extends BaseValidator { } + public boolean isAbstractType(List list) { + if (list.size() != 1) { + return false; + } else { + StructureDefinition sd = context.fetchTypeDefinition(list.get(0).getCode()); + return sd != null && sd.getAbstract(); + } + + } + public boolean validateStructureMap(List errors, Element src, NodeStack stack) { boolean ok = true; List imports = src.getChildrenByName("import"); @@ -314,6 +327,7 @@ public class StructureMapValidator extends BaseValidator { cc++; } + List grpNames = new ArrayList<>(); List groups = src.getChildrenByName("group"); // we iterate the groups repeatedly, validating them if they have stated types or found types, until nothing happens boolean fired = false; @@ -325,7 +339,7 @@ public class StructureMapValidator extends BaseValidator { if (hasInputTypes(group) || group.hasUserData("structuremap.parameters")) { group.setUserData("structuremap.validated", true); fired = true; - ok = validateGroup(errors, src, group, stack.push(group, cc, null, null)) && ok; + ok = validateGroup(errors, src, group, stack.push(group, cc, null, null), grpNames) && ok; } } cc++; @@ -336,7 +350,7 @@ public class StructureMapValidator extends BaseValidator { for (Element group : groups) { if (!group.hasUserData("structuremap.validated")) { hint(errors, "2023-03-01", IssueType.INFORMATIONAL, group.line(), group.col(), stack.push(group, cc, null, null).getLiteralPath(), ok, I18nConstants.SM_ORPHAN_GROUP, group.getChildValue("name")); - ok = validateGroup(errors, src, group, stack.push(group, cc, null, null)) && ok; + ok = validateGroup(errors, src, group, stack.push(group, cc, null, null), grpNames) && ok; } cc++; } @@ -369,13 +383,16 @@ public class StructureMapValidator extends BaseValidator { return true; } - private boolean validateGroup(List errors, Element src, Element group, NodeStack stack) { + private boolean validateGroup(List errors, Element src, Element group, NodeStack stack, List grpNames) { String name = group.getChildValue("name"); boolean ok = rule(errors, "2023-03-01", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), idIsValid(name), I18nConstants.SM_NAME_INVALID, name); + if (!rule(errors, "2023-03-01", IssueType.INVALID, group.line(), group.col(), stack.getLiteralPath(), !grpNames.contains(name), I18nConstants.SM_GROUP_NAME_DUPLICATE, name)) { + grpNames.add(name); + } Element extend = group.getNamedChild("extends"); if (extend != null) { - StructureMapGroupComponent grp = resolveGroup(extend.primitiveValue(), src); + ResolvedGroup grp = resolveGroup(extend.primitiveValue(), src); if (rule(errors, "2023-03-01", IssueType.NOTSUPPORTED, extend.line(), extend.col(), stack.push(extend, -1, null, null).getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, extend.primitiveValue())) { // check inputs } else { @@ -406,7 +423,7 @@ public class StructureMapValidator extends BaseValidator { return ok; } - private StructureMapGroupComponent resolveGroup(String grpName, Element src) { + private ResolvedGroup resolveGroup(String grpName, Element src) { if (grpName == null) { return null; } @@ -414,13 +431,13 @@ public class StructureMapValidator extends BaseValidator { for (Element group : groups) { String name = group.getChildValue("name"); if (grpName.equals(name)) { - return makeGroupComponent(group); - } + return new ResolvedGroup(null, makeGroupComponent(group)); + } } for (StructureMap map : imports) { for (StructureMapGroupComponent grp : map.getGroup()) { if (grpName.equals(grp.getName())) { - return grp; + return new ResolvedGroup(map, grp); } } } @@ -724,7 +741,7 @@ public class StructureMapValidator extends BaseValidator { String exp = params.get(0).getChildValue("value"); if (rule(errors, "2023-03-01", IssueType.INVALID, params.get(0).line(), params.get(0).col(), stack.getLiteralPath(), exp != null, I18nConstants.SM_TARGET_TRANSFORM_PARAM_UNPROCESSIBLE, "0", params.size())) { try { - TypeDetails td = fpe.check(variables, v.getSd().getType(), v.getEd().getPath(), fpe.parse(exp)); + TypeDetails td = fpe.check(variables, v.getSd().getUrl(), v.getEd().getPath(), fpe.parse(exp)); if (td.getTypes().size() == 1) { type = td.getType(); } @@ -976,7 +993,9 @@ public class StructureMapValidator extends BaseValidator { private void getElementDefinitionChildrenFromTypes(List result, StructureDefinition sd, ElementDefinition ed, String type, String element) { for (TypeRefComponent td : ed.getType()) { - if (type == null | td.getWorkingCode().equals(type)) { + String tn = td.getWorkingCode(); + StructureDefinition sdt = context.fetchTypeDefinition(tn); + if (type == null || tn.equals(type) || (sdt != null && sdt.getType().equals(type))) { StructureDefinition tsd = context.fetchTypeDefinition(td.getWorkingCode()); if (tsd != null) { for (ElementDefinition t : tsd.getSnapshot().getElement()) { @@ -1027,20 +1046,22 @@ public class StructureMapValidator extends BaseValidator { } } } else { - StructureMapGroupComponent grp = resolveGroup(name, src); + ResolvedGroup grp = resolveGroup(name, src); if (rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, name)) { List params = dependent.getChildren("parameter"); - if (rule(errors, "2023-03-01", IssueType.INVALID, dependent.line(), dependent.col(), stack.getLiteralPath(), params.size() == grp.getInput().size(), I18nConstants.SM_RULEGROUP_NOT_FOUND, params.size(), grp.getInput().size())) { + if (rule(errors, "2023-03-01", IssueType.INVALID, dependent.line(), dependent.col(), stack.getLiteralPath(), params.size() == grp.getTargetGroup().getInput().size(), I18nConstants.SM_RULEGROUP_NOT_FOUND, params.size(), grp.getTargetGroup().getInput().size())) { VariableSet lvars = new VariableSet(); int cc = 0; for (Element param : params) { NodeStack pstack = stack.push(param, cc, null, null); - StructureMapGroupInputComponent input = grp.getInput().get(cc); + StructureMapGroupInputComponent input = grp.getTargetGroup().getInput().get(cc); + String iType = resolveType(grp, input, src); String pname = input.getName(); VariableDefn v = getParameter(errors, param, pstack, variables, input.getMode()); if (v != null) { - if (rule(errors, "2023-03-01", IssueType.INVALID, param.line(), param.col(), pstack.getLiteralPath(), v.mode.equals(input.getMode().toCode()), I18nConstants.SM_DEPENDENT_PARAM_MODE_MISMATCH, param.getChildValue("name"), v.mode, input.getMode().toCode()) && - rule(errors, "2023-03-01", IssueType.INVALID, param.line(), param.col(), pstack.getLiteralPath(), typesMatch(v, input.getType()), I18nConstants.SM_DEPENDENT_PARAM_TYPE_MISMATCH, param.getChildValue("name"), v, input.getType())) { + if (rule(errors, "2023-03-01", IssueType.INVALID, param.line(), param.col(), pstack.getLiteralPath(), v.mode.equals(input.getMode().toCode()), I18nConstants.SM_DEPENDENT_PARAM_MODE_MISMATCH, param.getChildValue("name"), v.mode, input.getMode().toCode(), grp.getTargetGroup().getName()) && + rule(errors, "2023-03-01", IssueType.INVALID, param.line(), param.col(), pstack.getLiteralPath(), typesMatch(v, iType), I18nConstants.SM_DEPENDENT_PARAM_TYPE_MISMATCH, + pname, v.summary(), input.getType(), grp.getTargetGroup().getName(), input.getType(), grp.getTargetMap() == null ? "$this" : grp.getTargetMap().getVersionedUrl())) { lvars.add(pname, v); } else { ok = false; @@ -1050,11 +1071,11 @@ public class StructureMapValidator extends BaseValidator { } cc++; } - if (ok && grp.hasUserData("element.source")) { - Element g = (Element) grp.getUserData("element.source"); + if (ok && grp.getTargetGroup().hasUserData("element.source")) { + Element g = (Element) grp.getTargetGroup().getUserData("element.source"); if (g.hasUserData("structuremap.parameters")) { VariableSet pvars = (VariableSet) g.getUserData("structuremap.parameters"); - rule(errors, "2023-03-01", IssueType.INVALID, dependent.line(), dependent.col(), stack.getLiteralPath(), pvars.matches(lvars), I18nConstants.SM_DEPENDENT_PARAM_TYPE_MISMATCH_DUPLICATE, grp.getName(), pvars.summary(), lvars.summary()); + rule(errors, "2023-03-01", IssueType.INVALID, dependent.line(), dependent.col(), stack.getLiteralPath(), pvars.matches(lvars), I18nConstants.SM_DEPENDENT_PARAM_TYPE_MISMATCH_DUPLICATE, grp.getTargetGroup().getName(), pvars.summary(), lvars.summary()); } else { g.setUserData("structuremap.parameters", lvars); } @@ -1067,6 +1088,25 @@ public class StructureMapValidator extends BaseValidator { return ok; } + private String resolveType(ResolvedGroup grp, StructureMapGroupInputComponent input, Element map) { + if (grp.getTargetMap() == null) { + List structures = map.getChildrenByName("structure"); + for (Element structure : structures) { + String alias = structure.getChildValue("alias"); + if (alias != null && alias.equals(input.getType())) { + return structure.getChildValue("url"); + } + } + } else { + for (StructureMapStructureComponent struc : grp.getTargetMap().getStructure()) { + if (struc.hasAlias() && struc.getAlias().equals(input.getType())) { + return struc.getUrl(); + } + } + } + return input.getType(); + } + private StructureMapGroupComponent findDefaultGroup(Element src, String srcType, String tgtType) { List groups = src.getChildrenByName("group"); for (Element group : groups) { @@ -1126,9 +1166,16 @@ public class StructureMapValidator extends BaseValidator { } private boolean typesMatch(VariableDefn v, String type) { - if (type == null) { + if (type == null || !v.hasTypeInfo()) { + return true; + } else if (v.getSd().getUrl().equals(type) || v.getSd().getType().equals(type)) { return true; } else { + for (TypeRefComponent tr : v.getEd().getType()) { + if (type.equals(tr.getWorkingCode()) || type.equals("http://hl7.org/fhir/StructureDefinition/"+tr.getWorkingCode())) { + return true; + } + } return false; } } diff --git a/pom.xml b/pom.xml index 392a65b72..3bb359ca2 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 6.2.1 - 1.2.16 + 1.2.17-SNAPSHOT 5.7.1 1.8.2 3.0.0-M5