autofix slice names + check differentials

This commit is contained in:
Grahame Grieve 2020-01-27 21:08:17 +11:00
parent ee6e0d90de
commit 06d6d9452a
1 changed files with 68 additions and 3 deletions

View File

@ -265,6 +265,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private ValidationOptions terminologyServiceOptions = new ValidationOptions();
private boolean newSlicingProcessing;
private String defWebRoot;
private boolean autoFixSliceNames;
public ProfileUtilities(IWorkerContext context, List<ValidationMessage> messages, ProfileKnowledgeProvider pkp) {
super();
@ -281,11 +282,21 @@ public class ProfileUtilities extends TranslatingUtilities {
return igmode;
}
public void setIgmode(boolean igmode) {
this.igmode = igmode;
}
public boolean isAutoFixSliceNames() {
return autoFixSliceNames;
}
public ProfileUtilities setAutoFixSliceNames(boolean autoFixSliceNames) {
this.autoFixSliceNames = autoFixSliceNames;
return this;
}
public interface ProfileKnowledgeProvider {
public class BindingResolution {
public String display;
@ -479,6 +490,8 @@ public class ProfileUtilities extends TranslatingUtilities {
derived.setSnapshot(new StructureDefinitionSnapshotComponent());
try {
checkDifferential(derived.getDifferential().getElement(), derived.getType(), derived.getUrl());
// so we have two lists - the base list, and the differential list
// the differential list is only allowed to include things that are in the base list, but
// is allowed to include them multiple times - thereby slicing them
@ -611,6 +624,54 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
private void checkDifferential(List<ElementDefinition> elements, String type, String url) {
boolean first = true;
for (ElementDefinition ed : elements) {
if (!ed.hasPath()) {
throw new FHIRException("No path on element in differential in "+url);
}
String p = ed.getPath();
if (p == null) {
throw new FHIRException("No path value on element in differential in "+url);
}
if (!((first && type.equals(p)) || p.startsWith(type+"."))) {
throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": must start with "+type+"."+(first ? " (o be '"+type+"')" : ""));
}
if (p.contains(".")) {
// Element names (the parts of a path delineated by the '.' character) SHALL NOT contain whitespace (i.e. Unicode characters marked as whitespace)
// Element names SHALL NOT contain the characters ,:;'"/|?!@#$%^&*()[]{}
// Element names SHOULD not contain non-ASCII characters
// Element names SHALL NOT exceed 64 characters in length
String[] pl = p.split("\\.");
for (String pp : pl) {
if (pp.length() < 1) {
throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": name portion mising ('..')");
}
if (pp.length() > 64) {
throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": name portion exceeds 64 chars in length");
}
for (char ch : pp.toCharArray()) {
if (Character.isWhitespace(ch)) {
throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": no unicode whitespace");
}
if (Utilities.existsInList(ch, ',', ':', ';', '\'', '"', '/', '|', '?', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '{', '}')) {
throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": illegal character '"+ch+"'");
}
if (ch < ' ' || ch > 'z') {
throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": illegal character '"+ch+"'");
}
}
if (pp.contains("[") || pp.contains("]")) {
if (!pp.endsWith("[x]") || (pp.substring(0, pp.length()-3).contains("[") || (pp.substring(0, pp.length()-3).contains("]")))) {
throw new FHIRException("Illegal path '"+p+"' in differential in "+url+": illegal characters []");
}
}
}
}
}
}
private boolean isCompatibleType(String base, String type) {
StructureDefinition sd = context.fetchTypeDefinition(type);
while (sd != null) {
@ -958,7 +1019,11 @@ public class ProfileUtilities extends TranslatingUtilities {
if (!ts.defn.hasSliceName()) {
ts.defn.setSliceName(tn);
} else if (!ts.defn.getSliceName().equals(tn)) {
throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice name must be '"+tn+"' but is '"+ts.defn.getSliceName()+"'");
if (autoFixSliceNames) {
ts.defn.setSliceName(tn);
} else {
throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice name must be '"+tn+"' but is '"+ts.defn.getSliceName()+"'");
}
} if (!ts.defn.hasType()) {
ts.defn.addType().setCode(ts.type);
} else if (ts.defn.getType().size() > 1) {
@ -2424,7 +2489,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (messages == null) {
throw new FHIRException("Error at "+purl+"#"+derived.getPath()+": The target profile "+url+" is not valid constraint on the base ("+td.getTargetProfile()+")");
} else {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, derived.getPath(), "The target profile "+u.getValue()+" is not a valid constraint on the base ("+td.getTargetProfile()+")", IssueSeverity.ERROR));
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.BUSINESSRULE, derived.getPath(), "The target profile "+u.getValue()+" is not a valid constraint on the base ("+td.getTargetProfile()+") at "+derived.getPath(), IssueSeverity.ERROR));
}
}
}