Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2023 10 gg template #1467

Merged
merged 10 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public org.hl7.fhir.r5.model.Resource loadResource(InputStream stream, boolean i
if (killPrimitives) {
throw new FHIRException("Cannot kill primitives when using deferred loading");
}
if (r5 instanceof StructureDefinition && VersionUtilities.isR4BVer(version)) {
if (r5 instanceof StructureDefinition) {
r5 = new StructureDefinitionHacker(version).fixSD((StructureDefinition) r5);
}
if (patchUrls) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public org.hl7.fhir.r5.model.Resource loadResource(InputStream stream, boolean i
if (killPrimitives) {
throw new FHIRException("Cannot kill primitives when using deferred loading");
}
if (r5 instanceof StructureDefinition && VersionUtilities.isR4Ver(version)) {
if (r5 instanceof StructureDefinition) {
r5 = new StructureDefinitionHacker(version).fixSD((StructureDefinition) r5);
}
if (patchUrls) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,29 @@ public Resource fixSD(StructureDefinition sd) {
}
}
}
if (sd.getUrl().startsWith("http://hl7.org/fhir/uv/subscriptions-backport")) {
for (ElementDefinition ed : sd.getDifferential().getElement()) {
fixMarkdownR4BURLs(ed);
}
for (ElementDefinition ed : sd.getSnapshot().getElement()) {
fixMarkdownR4BURLs(ed);
}
}
return sd;
}

private void fixMarkdownR4BURLs(ElementDefinition ed) {
if (ed.hasDefinition()) {
ed.setDefinition(ed.getDefinition().replace("http://hl7.org/fhir/R4B/", "http://hl7.org/fhir/R4/"));
}
if (ed.hasComment()) {
ed.setComment(ed.getComment().replace("http://hl7.org/fhir/R4B/", "http://hl7.org/fhir/R4/"));
}
if (ed.hasRequirements()) {
ed.setRequirements(ed.getRequirements().replace("http://hl7.org/fhir/R4B/", "http://hl7.org/fhir/R4/"));
}
}

private void fixDocSecURL(ElementDefinition ed) {
for (TypeRefComponent tr : ed.getType()) {
for (CanonicalType c : tr.getProfile()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2356,6 +2356,9 @@ protected void updateFromDefinition(ElementDefinition dest, ElementDefinition so
}
}
if (profile != null) {
if (profile.getSnapshot().getElement().isEmpty()) {
throw new DefinitionException(context.formatMessage(I18nConstants.SNAPSHOT_IS_EMPTY, profile.getVersionedUrl()));
}
ElementDefinition e = profile.getSnapshot().getElement().get(0);
String webroot = profile.getUserString("webroot");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2546,7 +2546,7 @@ public StructureDefinition fetchTypeDefinition(String typeName) {
}
} catch (Exception e) {
// not sure what to do in this case?
System.out.println("Unable to generate snapshot @4 for "+p.getVersionedUrl()+": "+e.getMessage());
System.out.println("Unable to generate snapshot @5 for "+p.getVersionedUrl()+": "+e.getMessage());
if (logger.isDebugLogging()) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,5 +424,16 @@ public StructureDefinition findType(String typeName) {
return null;
}

public StructureDefinition fetchProfileByIdentifier(String tid) {
for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) {
for (Identifier ii : sd.getIdentifier()) {
if (tid.equals(ii.getValue())) {
return sd;
}
}
}
return null;
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -1488,4 +1488,15 @@ public Element setNativeObject(Object nativeObject) {
return this;
}

public void removeExtension(String url) {
List<Element> rem = new ArrayList<>();
for (Element e : children) {
if ("extension".equals(e.getName()) && url.equals(e.getChildValue("url"))) {
rem.add(e);
}
}
children.removeAll(rem);
}


}
12 changes: 11 additions & 1 deletion org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Base.java
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,17 @@ public ValidationInfo addDefinition(StructureDefinition structure, ElementDefini
return vi;
}



public boolean hasValidated(StructureDefinition sd, ElementDefinition ed) {
if (validationInfo != null) {
for (ValidationInfo vi : validationInfo) {
if (vi.definition == ed && vi.structure == sd) {
return true;
}
}
}
return false;
}

// validation messages: the validator does not populate these (yet)
public Base addValidationMessage(ValidationMessage msg) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,9 +721,9 @@ public List<String> getDistalNames() {
} else if (group != null) {
names.addAll(group.getDistalNames());
} else if (function != null) {
names.addAll(null);
names.add(null);
} else if (constant != null) {
names.addAll(null);
names.add(null);
} else {
names.add(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ public class ToolingExtensions {
public static final String EXT_ID_CHOICE_GROUP = "http://hl7.org/fhir/tools/StructureDefinition/xml-choice-group";
public static final String EXT_DATE_RULES = "http://hl7.org/fhir/tools/StructureDefinition/elementdefinition-date-rules";
public static final String EXT_PROFILE_STYLE = "http://hl7.org/fhir/tools/StructureDefinition/type-profile-style";
public static final String EXT_RESOURCE_NAME = "http://hl7.org/fhir/StructureDefinition/resource-instance-name";
public static final String EXT_RESOURCE_DESC = "http://hl7.org/fhir/StructureDefinition/resource-instance-description";
public static final String EXT_ARTIFACT_NAME = "http://hl7.org/fhir/StructureDefinition/artifact-name";
public static final String EXT_ARTIFACT_DESC = "http://hl7.org/fhir/StructureDefinition/artifact-description";

// specific extension helpers

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,26 +226,28 @@ private void checkColumn(String path, JsonObject column, TypeDetails t) {
warning(path+".path", expression, s);
}
String columnName = null;
JsonElement aliasJ = column.get("alias");
if (aliasJ != null) {
if (aliasJ instanceof JsonString) {
columnName = aliasJ.asString();
JsonElement nameJ = column.get("name");
if (nameJ != null) {
if (nameJ instanceof JsonString) {
columnName = nameJ.asString();
if (!isValidName(columnName)) {
error(path+".name", aliasJ, "The name '"+columnName+"' is not valid", IssueType.VALUE);
error(path+".name", nameJ, "The name '"+columnName+"' is not valid", IssueType.VALUE);
}
} else {
error(path+".alias", aliasJ, "alias must be a string", IssueType.INVALID);
error(path+".name", nameJ, "name must be a string", IssueType.INVALID);
}
}
if (columnName == null) {
List<String> names = node.getDistalNames();
if (names.size() == 1 && names.get(0) != null) {
columnName = names.get(0);
if (!isValidName(columnName)) {
error(path+".path", expression, "The name '"+columnName+"' found in the path expression is not a valid column name, so an alias is required", IssueType.INVARIANT);
error(path+".path", expression, "A column name is required. The natural name to chose is '"+columnName+"' (from the path)", IssueType.INVARIANT);
} else {
error(path, column, "A column name is required", IssueType.REQUIRED);
}
} else {
error(path, column, "The path does not resolve to a name, so an alias is required", IssueType.REQUIRED);
error(path, column, "A column name is required", IssueType.REQUIRED);
}
}
// ok, name is sorted!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,8 @@ public class I18nConstants {
public static final String XSI_TYPE_WRONG = "XSI_TYPE_WRONG";
public static final String XSI_TYPE_UNNECESSARY = "XSI_TYPE_UNNECESSARY";
public static final String TERMINOLOGY_TX_OID_MULTIPLE_MATCHES = "TERMINOLOGY_TX_OID_MULTIPLE_MATCHES";
public static final String CDA_UNKNOWN_TEMPLATE = "CDA_UNKNOWN_TEMPLATE";
public static final String CDA_UNKNOWN_TEMPLATE_EXT = "CDA_UNKNOWN_TEMPLATE_EXT";
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ public String getFolder() {
}

private NpmPackage loadPackageInfo(String path) throws IOException {
File f = new File(Utilities.path(path, "usage.ini"));
JsonObject j = f.exists() ? JsonParser.parseObject(f) : new JsonObject();
j.set("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
JsonParser.compose(j, f, true);

NpmPackage pi = minimalMemory ? NpmPackage.fromFolderMinimal(path) : NpmPackage.fromFolder(path);
return pi;
}
Expand Down
6 changes: 4 additions & 2 deletions org.hl7.fhir.utilities/src/main/resources/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ ED_INVARIANT_KEY_ALREADY_USED = The constraint key ''{0}'' already exists in the
ED_INVARIANT_NO_EXPRESSION = The constraint ''{0}'' has no computable expression, so validators will not be able to check it
ED_INVARIANT_EXPRESSION_CONFLICT = The constraint ''{0}'' has an expression ''{1}'', which differs from the earlier expression provided of ''{2}'' (invariants are allowed to repeat, but cannot differ)
ED_INVARIANT_EXPRESSION_ERROR = Error in constraint ''{0}'' with expression ''{1}'': {2}
SNAPSHOT_IS_EMPTY = The snapshot for the profile ''{0}'' is empty (which should not happen)
SNAPSHOT_IS_EMPTY = The snapshot for the profile ''{0}'' is empty. This is usually due to a processing logged elsewhere
TERMINOLOGY_TX_HINT = {1}
TERMINOLOGY_TX_WARNING = {1}
SD_ED_TYPE_WRONG_TYPE_one = The element has a type {0} which is different to the type {1} on the base profile {2}
Expand Down Expand Up @@ -1062,8 +1062,10 @@ LOGICAL_MODEL_QNAME_MISMATCH = The QName ''{0}'' does not match the expected QNa
FHIRPATH_CHOICE_NO_TYPE_SPECIFIER = The expression ''{0}'' refers to an element that is a choice, but doesn''t have an .ofType() so that SQL view runners can pre-determine the full element name
FHIRPATH_CHOICE_SPURIOUS_TYPE_SPECIFIER = The expression ''{0}'' refers to an element that is not a choice, but has an .ofType(). SQL view runners are likely to pre-determine an incorrect full element name
FHIRPATH_NOT_A_COLLECTION = Found a use of a collection operator on something that is not a collection at ''{0}'' - check that there's no mistakes in the expression syntax
TERMINOLOGY_TX_UNKNOWN_OID = The OID ''{0}'' is not known
TERMINOLOGY_TX_UNKNOWN_OID = The OID ''{0}'' is not known, so the code can't be validated
TERMINOLOGY_TX_SYSTEM_NO_CODE = A code with no system has no defined meaning, and it cannot be validated. A system should be provided
XSI_TYPE_WRONG = The xsi:type value ''{0}'' is wrong (should be ''{1}''). Note that xsi:type is unnecessary at this point
XSI_TYPE_UNNECESSARY = xsi:type is unnecessary at this point
TERMINOLOGY_TX_OID_MULTIPLE_MATCHES = The OID ''{0}'' matches multiple code systems ({1})
CDA_UNKNOWN_TEMPLATE = The CDA Template {0} is not known
CDA_UNKNOWN_TEMPLATE_EXT = The CDA Template {0} / {1} is not known
Original file line number Diff line number Diff line change
Expand Up @@ -502,12 +502,14 @@ public FHIRPathEngine getFHIRPathEngine() {
public boolean testMode;
private boolean example ;
private IDigitalSignatureServices signatureServices;
private ContextUtilities cu;

public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) {
super(theContext, xverManager, false);
start = System.currentTimeMillis();
this.externalHostServices = hostServices;
this.profileUtilities = new ProfileUtilities(theContext, null, null);
cu = new ContextUtilities(theContext);
fpe = new FHIRPathEngine(context);
validatorServices = new ValidatorHostServices();
fpe.setHostServices(validatorServices);
Expand Down Expand Up @@ -1662,7 +1664,7 @@ private boolean convertCDACodeToCodeableConcept(List<ValidationMessage> errors,
c.setSystem("urn:oid:"+oid);
ok = false;
if (urls.size() == 0) {
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_UNKNOWN_OID, oid);
warning(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_UNKNOWN_OID, oid);
} else {
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_OID_MULTIPLE_MATCHES, oid, CommaSeparatedStringBuilder.join(",", urls));
}
Expand Down Expand Up @@ -5799,6 +5801,25 @@ private boolean validateElement(ValidationContext valContext, List<ValidationMes
ok = checkChild(valContext, errors, profile, definition, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, ei, extensionUrl, pct, mode) && ok;
}
vi.setValid(ok);


if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_PROFILE_STYLE) && "cda".equals(ToolingExtensions.readStringExtension(profile, ToolingExtensions.EXT_PROFILE_STYLE))) {
List<Element> templates = element.getChildren("templateId");
for (Element t : templates) {
String tid = "urn:hl7ii:"+t.getChildValue("root")+(t.hasChild("extension") ? ":"+t.getChildValue("extension") : "");
StructureDefinition sd = cu.fetchProfileByIdentifier(tid);
if (sd == null) {
ok = rule(errors, "2023-10-20", IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), false, t.hasChild("extension") ? I18nConstants.CDA_UNKNOWN_TEMPLATE_EXT : I18nConstants.CDA_UNKNOWN_TEMPLATE, t.getChildValue("root"), t.getChildValue("extension")) && ok;
} else {
ElementDefinition ed = sd.getSnapshot().getElementFirstRep();
if (!element.hasValidated(sd, ed)) {
element.addMessage(signpost(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST, sd.getVersionedUrl()));
ok = validateElement(valContext, errors, sd, ed, null, null, resource, element, actualType, stack, inCodeableConcept, checkDisplayInContext, extensionUrl, pct, mode) && ok;
}
}
}
}

return ok;
}

Expand Down Expand Up @@ -6060,13 +6081,15 @@ public boolean checkChildByDefinition(ValidationContext valContext, List<Validat
if (defn != null && defn.hasExtension(ToolingExtensions.EXT_BINDING_STYLE)) {
String style = ToolingExtensions.readStringExtension(defn, ToolingExtensions.EXT_BINDING_STYLE);
if ("CDA".equals(style)) {
if (cdaTypeIs(defn, "CS")) {
ok = checkCDACodeSimple(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
} else if (cdaTypeIs(defn, "CV") || cdaTypeIs(defn, "PQ")) {
ok = checkCDACoding(errors, ei.getPath(), cdaTypeIs(defn, "PQ"), ei.getElement(), profile, checkDefn, stack, defn, inCodeableConcept, checkDisplayInContext) && ok;
} else if (cdaTypeIs(defn, "CD") || cdaTypeIs(defn, "CE")) {
ok = checkCDACodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
thisIsCodeableConcept = true;
if (!ei.getElement().hasChild("nullFlavor")) {
if (cdaTypeIs(defn, "CS")) {
ok = checkCDACodeSimple(valContext, errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
} else if (cdaTypeIs(defn, "CV") || cdaTypeIs(defn, "PQ")) {
ok = checkCDACoding(errors, ei.getPath(), cdaTypeIs(defn, "PQ"), ei.getElement(), profile, checkDefn, stack, defn, inCodeableConcept, checkDisplayInContext) && ok;
} else if (cdaTypeIs(defn, "CD") || cdaTypeIs(defn, "CE")) {
ok = checkCDACodeableConcept(errors, ei.getPath(), ei.getElement(), profile, checkDefn, stack, defn) && ok;
thisIsCodeableConcept = true;
}
}
}
}
Expand Down Expand Up @@ -6180,15 +6203,15 @@ private boolean checkCDACoding(List<ValidationMessage> errors, String path, bool
boolean ok = true;
String system = null;
String code = element.getNamedChildValue(isPQ ? "unit" : "code");
String oid = element.getNamedChildValue("codeSystem");
String oid = isPQ ? "2.16.840.1.113883.6.8" : element.getNamedChildValue("codeSystem");
if (oid != null) {
Set<String> urls = context.urlsForOid(true, oid);
if (urls.size() != 1) {
system = "urn:oid:"+oid;
ok = false;

if (urls.size() == 0) {
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_UNKNOWN_OID, oid);
warning(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_UNKNOWN_OID, oid);
} else {
rule(errors, "2023-10-11", IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_OID_MULTIPLE_MATCHES, oid, CommaSeparatedStringBuilder.join(",", urls));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ private boolean validateGroupElementTarget(List<ValidationMessage> errors, Eleme
}
}
} else {
ok = (ctxt.source.cs.getContent() != CodeSystemContentMode.COMPLETE) & ok;
ok = (ctxt.target.cs.getContent() != CodeSystemContentMode.COMPLETE) & ok;
}
} else {
addToBatch(code, cstack, ctxt.target, ctxt.targetScope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ public JsonObjectPair(JsonObject suite, JsonObject test) {
}

private static final String SERVER = FhirSettings.getTxFhirDevelopment();
// private static final String SERVER = FhirSettings.getTxFhirLocal();
// private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir";


@Parameters(name = "{index}: id {0}")
Expand Down
Loading