Merge pull request #711 from hapifhir/gg-202201-comparison-fixes

Gg 202201 comparison fixes
This commit is contained in:
Grahame Grieve 2022-01-14 11:24:02 +11:00 committed by GitHub
commit 336cc288a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 372 additions and 99 deletions

1
.gitignore vendored
View File

@ -304,3 +304,4 @@ local.properties
/org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical2-actual.xml
/org.hl7.fhir.r5.new
/org.hl7.fhir.r5.newc
/org.hl7.fhir.r4b.new

View File

@ -162,6 +162,7 @@ compile group: 'ca.uhn.hapi.fhir', name: 'hapi-fhir-structures-r4', version: '(l
compile group: 'ca.uhn.hapi.fhir', name: 'hapi-fhir-structures-r5', version: '(latest version)'
```
Note that the built binary validator is released through GitHub releases.
### Maintenance
This project is maintained by [Grahame Grieve][Link-grahameGithub], [James Agnew][Link-jamesGithub] and [Mark Iantorno][Link-markGithub] on behalf of the FHIR community.

View File

@ -0,0 +1,74 @@
package org.hl7.fhir.convertors.misc;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r4b.formats.JsonParser;
import org.hl7.fhir.r4b.model.Bundle;
import org.hl7.fhir.r4b.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.json.JsonTrackingParser;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.hl7.fhir.r4b.model.SearchParameter;
import org.hl7.fhir.r4b.utils.NPMPackageGenerator;
import org.hl7.fhir.r4b.utils.NPMPackageGenerator.Category;
public class ExamplesPackageBuilder {
public static void main(String[] args) throws FHIRFormatError, FileNotFoundException, IOException {
new ExamplesPackageBuilder().process(args[0]);
}
private void process(String source) throws FHIRFormatError, FileNotFoundException, IOException {
Set<String> set = new HashSet<>();
for (File f : new File(source).listFiles()) {
if (f.getName().endsWith(".json")) {
JsonObject obj = JsonTrackingParser.parseJson(new FileInputStream(f));
if (obj.has("resourceType") && obj.has("id")) {
String type = obj.get("resourceType").getAsString();
String id = obj.get("id").getAsString();
byte[] content = TextFile.fileToBytes(f);
if (type.equals("ConceptMap")) {
System.out.println("convert "+f.getName());
content = r5ToR4B(content);
TextFile.bytesToFile(content, f);
}
// TextFile.bytesToFile(content, Utilities.path(dest2, type+"-"+id+".json"));
// if (!set.contains(type+"/"+id)) {
// set.add(type+"/"+id);
// pck.addFile(Category.RESOURCE, type+"-"+id+".json", content);
// }
}
}
}
// pck.finish();
//
}
private byte[] r5ToR4B(byte[] content) throws FHIRFormatError, IOException {
try {
org.hl7.fhir.r5.model.Resource r5 = new org.hl7.fhir.r5.formats.JsonParser().parse(content);
org.hl7.fhir.r4.model.Resource r4 = VersionConvertorFactory_40_50.convertResource(r5);
return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(r4);
} catch (Exception e) {
System.out.println(" .. failed: "+e.getMessage());
return content;
}
}
}

View File

@ -0,0 +1,87 @@
package org.hl7.fhir.core.generator.engine;
import java.io.IOException;
import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r4.formats.JsonParser;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CompartmentDefinition;
import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.OperationDefinition;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.SearchParameter;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.npm.ToolsVersion;
public class DefinitionsLoaderR4B {
public static Definitions load(NpmPackage npm) throws IOException {
Definitions res = new Definitions();
for (String t : npm.listResources("CodeSystem")) {
res.getCodeSystems().see((CodeSystem) load(npm, t), null);
}
for (String t : npm.listResources("ValueSet")) {
res.getValuesets().see((ValueSet) load(npm, t), null);
}
for (String t : npm.listResources("ConceptMap")) {
res.getConceptMaps().see((ConceptMap) load(npm, t), null);
}
for (String t : npm.listResources("CapabilityStatement")) {
res.getStatements().see((CapabilityStatement) load(npm, t), null);
}
for (String t : npm.listResources("StructureDefinition")) {
res.getStructures().see((StructureDefinition) load(npm, t), null);
}
for (String t : npm.listResources("OperationDefinition")) {
res.getOperations().see((OperationDefinition) load(npm, t), null);
}
for (String t : npm.listResources("SearchParameter")) {
res.getSearchParams().see((SearchParameter) load(npm, t), null);
}
for (String t : npm.listResources("CompartmentDefinition")) {
res.getCompartments().see((CompartmentDefinition) load(npm, t), null);
}
// Bundle bnd = (Bundle) load(npm, "Bundle-searchParams.json");
// if (bnd != null) {
// for (BundleEntryComponent be : bnd.getEntry()) {
// Resource r = be.getResource();
// if (r instanceof CodeSystem) {
// res.getCodeSystems().see((CodeSystem) r, null);
// } else if (r instanceof ValueSet) {
// res.getValuesets().see((ValueSet) r, null);
// } else if (r instanceof ConceptMap) {
// res.getConceptMaps().see((ConceptMap) r, null);
// } else if (r instanceof CapabilityStatement) {
// res.getStatements().see((CapabilityStatement) r, null);
// } else if (r instanceof StructureDefinition) {
// res.getStructures().see((StructureDefinition) r, null);
// } else if (r instanceof OperationDefinition) {
// res.getOperations().see((OperationDefinition) r, null);
// } else if (r instanceof SearchParameter) {
// res.getSearchParams().see((SearchParameter) r, null);
// } else if (r instanceof CompartmentDefinition) {
// res.getCompartments().see((CompartmentDefinition) r, null);
// }
// }
// }
return res;
}
public static Resource load(NpmPackage npm, String t) {
try {
return VersionConvertorFactory_40_50.convertResource(new JsonParser().parse(npm.loadResource(t)));
} catch (Exception e) {
System.out.println("Error reading "+t+": "+e.getMessage());
e.printStackTrace();
return null;
}
}
}

View File

@ -1,6 +1,8 @@
package org.hl7.fhir.r4.utils.client.network;
import okhttp3.*;
import okio.Buffer;
import org.hl7.fhir.utilities.ToolingClientLogger;
import javax.annotation.Nonnull;
@ -26,8 +28,17 @@ public class FhirLoggingInterceptor implements Interceptor {
public Response intercept(@Nonnull Interceptor.Chain chain) throws IOException {
// Log Request
Request request = chain.request();
logger.logRequest(request.method(), request.url().toString(), new ArrayList<>(request.headers().names()),
request.body() != null ? request.body().toString().getBytes() : null);
List<String> hdrs = new ArrayList<>();
for (String s : request.headers().toString().split("\\n")) {
hdrs.add(s.trim());
}
byte[] cnt = null;
if (request.body() != null) {
Buffer buf = new Buffer();
request.body().writeTo(buf);
cnt = buf.readByteArray();
}
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
// Log Response
Response response = null;

View File

@ -1,6 +1,8 @@
package org.hl7.fhir.r4b.utils.client.network;
import okhttp3.*;
import okio.Buffer;
import org.hl7.fhir.utilities.ToolingClientLogger;
import javax.annotation.Nonnull;
@ -26,8 +28,17 @@ public class FhirLoggingInterceptor implements Interceptor {
public Response intercept(@Nonnull Interceptor.Chain chain) throws IOException {
// Log Request
Request request = chain.request();
logger.logRequest(request.method(), request.url().toString(), new ArrayList<>(request.headers().names()),
request.body() != null ? request.body().toString().getBytes() : null);
List<String> hdrs = new ArrayList<>();
for (String s : request.headers().toString().split("\\n")) {
hdrs.add(s.trim());
}
byte[] cnt = null;
if (request.body() != null) {
Buffer buf = new Buffer();
request.body().writeTo(buf);
cnt = buf.readByteArray();
}
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
// Log Response
Response response = null;

View File

@ -45,14 +45,14 @@ public class ProfileComparer extends CanonicalResourceComparer {
public class ProfileComparison extends CanonicalResourceComparison<StructureDefinition> {
private StructuralMatch<ElementDefinition> combined;
private StructuralMatch<ElementDefinitionNode> combined;
public ProfileComparison(StructureDefinition left, StructureDefinition right) {
super(left, right);
combined = new StructuralMatch<ElementDefinition>(); // base
combined = new StructuralMatch<ElementDefinitionNode>(); // base
}
public StructuralMatch<ElementDefinition> getCombined() {
public StructuralMatch<ElementDefinitionNode> getCombined() {
return combined;
}
@ -79,7 +79,21 @@ public class ProfileComparer extends CanonicalResourceComparer {
}
private class ElementDefinitionNode {
private ElementDefinition def;
private StructureDefinition src;
private ElementDefinitionNode(StructureDefinition src, ElementDefinition def) {
super();
this.src = src;
this.def = def;
}
public ElementDefinition getDef() {
return def;
}
public StructureDefinition getSrc() {
return src;
}
}
private ProfileUtilities utilsLeft;
private ProfileUtilities utilsRight;
@ -127,7 +141,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
if (left.getType().equals(right.getType())) {
DefinitionNavigator ln = new DefinitionNavigator(session.getContextLeft(), left);
DefinitionNavigator rn = new DefinitionNavigator(session.getContextRight(), right);
StructuralMatch<ElementDefinition> sm = new StructuralMatch<ElementDefinition>(ln.current(), rn.current());
StructuralMatch<ElementDefinitionNode> sm = new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(left, ln.current()), new ElementDefinitionNode(right, rn.current()));
compareElements(res, sm, ln.path(), null, ln, rn);
res.combined = sm;
}
@ -147,7 +161,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
throw new DefinitionException("StructureDefinition snapshot is empty ("+name+": "+sd.getName()+")");
}
private void compareElements(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException {
private void compareElements(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException {
assert(path != null);
assert(left != null);
assert(right != null);
@ -190,7 +204,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
subset.setExample(left.current().hasExample() ? left.current().getExample() : right.current().getExample());
if (left.current().getMustSupport() != right.current().getMustSupport()) {
vm(IssueSeverity.ERROR, "Elements differ in definition for mustSupport:\r\n \""+left.current().getMustSupport()+"\"\r\n \""+right.current().getMustSupport()+"\"", path, comp.getMessages(), res.getMessages());
vm(IssueSeverity.WARNING, "Elements differ in definition for mustSupport: '"+left.current().getMustSupport()+"' vs '"+right.current().getMustSupport()+"'", path, comp.getMessages(), res.getMessages());
}
subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport());
@ -198,15 +212,20 @@ public class ProfileComparer extends CanonicalResourceComparer {
// compare and intersect
superset.setMin(unionMin(left.current().getMin(), right.current().getMin()));
superset.setMax(unionMax(left.current().getMax(), right.current().getMax()));
subset.setMin(intersectMin(left.current().getMin(), right.current().getMin()));
subset.setMax(intersectMax(left.current().getMax(), right.current().getMax()));
rule(comp, res, subset.getMax().equals("*") || Integer.parseInt(subset.getMax()) >= subset.getMin(), path, "Cardinality Mismatch: "+card(left)+"/"+card(right));
int leftMin = left.current().getMin();
int rightMin = right.current().getMin();
int leftMax = "*".equals(left.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(left.current().getMax());
int rightMax = "*".equals(right.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(right.current().getMax());
checkMinMax(comp, res, path, leftMin, rightMin, leftMax, rightMax);
superset.setMin(unionMin(leftMin, rightMin));
superset.setMax(unionMax(leftMax, rightMax, left.current().getMax(), right.current().getMax()));
subset.setMin(intersectMin(leftMin, rightMin));
subset.setMax(intersectMax(leftMax, rightMax, left.current().getMax(), right.current().getMax()));
superset.getType().addAll(unionTypes(comp, res, path, left.current().getType(), right.current().getType()));
subset.getType().addAll(intersectTypes(comp, res, subset, path, left.current().getType(), right.current().getType()));
rule(comp, res, !subset.getType().isEmpty() || (!left.current().hasType() && !right.current().hasType()), path, "Type Mismatch:\r\n "+typeCode(left)+"\r\n "+typeCode(right));
rule(comp, res, !subset.getType().isEmpty() || (!left.current().hasType() && !right.current().hasType()), path, "Type Mismatch: "+typeCode(left)+" vs "+typeCode(right));
// <fixed[x]><!-- ?? 0..1 * Value must be exactly this --></fixed[x]>
// <pattern[x]><!-- ?? 0..1 * Value must have at least these property values --></pattern[x]>
superset.setMaxLengthElement(unionMaxLength(left.current().getMaxLength(), right.current().getMaxLength()));
@ -283,7 +302,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
// return null;
}
private void compareChildren(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException, FHIRFormatError {
private void compareChildren(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException, FHIRFormatError {
List<DefinitionNavigator> lc = left.children();
List<DefinitionNavigator> rc = right.children();
// it's possible that one of these profiles walks into a data type and the other doesn't
@ -299,10 +319,10 @@ public class ProfileComparer extends CanonicalResourceComparer {
DefinitionNavigator r = findInList(rc, l);
if (r == null) {
comp.getUnion().getSnapshot().getElement().add(l.current().copy());
res.getChildren().add(new StructuralMatch<ElementDefinition>(l.current(), vmI(IssueSeverity.INFORMATION, "Removed this element", path)));
res.getChildren().add(new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(l.getStructure(), l.current()), vmI(IssueSeverity.INFORMATION, "Removed this element", path)));
} else {
matchR.add(r);
StructuralMatch<ElementDefinition> sm = new StructuralMatch<ElementDefinition>(l.current(), r.current());
StructuralMatch<ElementDefinitionNode> sm = new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(l.getStructure(), l.current()), new ElementDefinitionNode(r.getStructure(), r.current()));
res.getChildren().add(sm);
compareElements(comp, sm, l.path(), null, l, r);
}
@ -310,7 +330,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
for (DefinitionNavigator r : rc) {
if (!matchR.contains(r)) {
comp.getUnion().getSnapshot().getElement().add(r.current().copy());
res.getChildren().add(new StructuralMatch<ElementDefinition>(vmI(IssueSeverity.INFORMATION, "Added this element", path), r.current()));
res.getChildren().add(new StructuralMatch<ElementDefinitionNode>(vmI(IssueSeverity.INFORMATION, "Added this element", path), new ElementDefinitionNode(r.getStructure(), r.current())));
}
}
}
@ -324,7 +344,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return null;
}
private void ruleEqual(ProfileComparison comp, StructuralMatch<ElementDefinition> res, DataType vLeft, DataType vRight, String name, String path) throws IOException {
private void ruleEqual(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, DataType vLeft, DataType vRight, String name, String path) throws IOException {
if (vLeft == null && vRight == null) {
// nothing
} else if (vLeft == null) {
@ -338,7 +358,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
private String toString(DataType val, boolean left) throws IOException {
if (val instanceof PrimitiveType)
return "\"" + ((PrimitiveType) val).getValueAsString()+"\"";
return "'" + ((PrimitiveType) val).getValueAsString()+"'";
IParser jp = left ? session.getContextLeft().newJsonParser() : session.getContextRight().newJsonParser();
return jp.composeString(val, "value");
@ -356,14 +376,14 @@ public class ProfileComparer extends CanonicalResourceComparer {
return s;
}
private boolean rule(ProfileComparison comp, StructuralMatch<ElementDefinition> res, boolean test, String path, String message) {
private boolean rule(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, boolean test, String path, String message) {
if (!test) {
vm(IssueSeverity.ERROR, message, path, comp.getMessages(), res.getMessages());
}
return test;
}
private String mergeText(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String name, String left, String right, boolean isError) {
private String mergeText(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, String name, String left, String right, boolean isError) {
if (left == null && right == null)
return null;
if (left == null)
@ -375,7 +395,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
if (left.equalsIgnoreCase(right))
return left;
if (path != null) {
vm(isError ? IssueSeverity.ERROR : IssueSeverity.WARNING, "Elements differ in "+name+":\r\n \""+left+"\"\r\n \""+right+"\"", path, comp.getMessages(), res.getMessages());
vm(isError ? IssueSeverity.ERROR : IssueSeverity.WARNING, "Elements differ in "+name+": '"+left+"' vs '"+right+"'", path, comp.getMessages(), res.getMessages());
}
return "left: "+left+"; right: "+right;
}
@ -429,6 +449,36 @@ public class ProfileComparer extends CanonicalResourceComparer {
return right;
}
private void checkMinMax(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, int leftMin, int rightMin, int leftMax, int rightMax) {
if (leftMin != rightMin) {
if (leftMin == 0) {
vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ: '"+leftMin+"' vs '"+rightMin+"'", path, comp.getMessages(), res.getMessages());
} else if (rightMin == 0) {
vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ: '"+leftMin+"' vs '"+rightMin+"'", path, comp.getMessages(), res.getMessages());
} else {
vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ: '"+leftMin+"' vs '"+rightMin+"'", path, comp.getMessages(), res.getMessages());
}
}
if (leftMax != rightMax) {
if (leftMax == Integer.MAX_VALUE) {
vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ: '"+leftMax+"' vs '"+rightMax+"'", path, comp.getMessages(), res.getMessages());
} else if (rightMax == Integer.MAX_VALUE) {
vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ: '"+leftMax+"' vs '"+rightMax+"'", path, comp.getMessages(), res.getMessages());
} else {
vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ: '"+leftMax+"' vs '"+rightMax+"'", path, comp.getMessages(), res.getMessages());
}
}
// rule(comp, res, subset.getMax().equals("*") || Integer.parseInt(subset.getMax()) >= subset.getMin(), path, "Cardinality Mismatch: "+card(left)+"/"+card(right));
// cross comparison - if max > min in either direction, there can be no instances that are valid against both
if (leftMax < rightMin) {
vm(IssueSeverity.ERROR, "Element minimum cardinalities conflict: '"+leftMin+".."+leftMax+"' vs '"+rightMin+".."+rightMax+"': No instances can be valid against both profiles", path, comp.getMessages(), res.getMessages());
}
if (rightMax < leftMin) {
vm(IssueSeverity.ERROR, "Element minimum cardinalities conflict: '"+leftMin+".."+leftMax+"' vs '"+rightMin+".."+rightMax+"': No instances can be valid against both profiles", path, comp.getMessages(), res.getMessages());
}
}
private int unionMin(int left, int right) {
if (left > right)
return right;
@ -436,18 +486,14 @@ public class ProfileComparer extends CanonicalResourceComparer {
return left;
}
private String intersectMax(String left, String right) {
int l = "*".equals(left) ? Integer.MAX_VALUE : Integer.parseInt(left);
int r = "*".equals(right) ? Integer.MAX_VALUE : Integer.parseInt(right);
private String intersectMax(int l, int r, String left, String right) {
if (l < r)
return left;
else
return right;
}
private String unionMax(String left, String right) {
int l = "*".equals(left) ? Integer.MAX_VALUE : Integer.parseInt(left);
int r = "*".equals(right) ? Integer.MAX_VALUE : Integer.parseInt(right);
private String unionMax(int l, int r, String left, String right) {
if (l < r)
return right;
else
@ -480,7 +526,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return Integer.toString(defn.current().getMin())+".."+defn.current().getMax();
}
private Collection<? extends TypeRefComponent> unionTypes(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> left, List<TypeRefComponent> right) throws DefinitionException, IOException, FHIRFormatError {
private Collection<? extends TypeRefComponent> unionTypes(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, List<TypeRefComponent> left, List<TypeRefComponent> right) throws DefinitionException, IOException, FHIRFormatError {
List<TypeRefComponent> result = new ArrayList<TypeRefComponent>();
for (TypeRefComponent l : left)
checkAddTypeUnion(comp, res, path, result, l, session.getContextLeft());
@ -489,7 +535,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return result;
}
private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> results, TypeRefComponent nw, IWorkerContext ctxt) throws DefinitionException, IOException, FHIRFormatError {
private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, List<TypeRefComponent> results, TypeRefComponent nw, IWorkerContext ctxt) throws DefinitionException, IOException, FHIRFormatError {
boolean pfound = false;
boolean tfound = false;
nw = nw.copy();
@ -586,7 +632,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return false;
}
private Collection<? extends TypeRefComponent> intersectTypes(ProfileComparison comp, StructuralMatch<ElementDefinition> res, ElementDefinition ed, String path, List<TypeRefComponent> left, List<TypeRefComponent> right) throws DefinitionException, IOException, FHIRFormatError {
private Collection<? extends TypeRefComponent> intersectTypes(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, ElementDefinition ed, String path, List<TypeRefComponent> left, List<TypeRefComponent> right) throws DefinitionException, IOException, FHIRFormatError {
List<TypeRefComponent> result = new ArrayList<TypeRefComponent>();
for (TypeRefComponent l : left) {
if (l.hasAggregation())
@ -665,7 +711,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return b.toString();
}
private boolean compareBindings(ProfileComparison comp, StructuralMatch<ElementDefinition> res, ElementDefinition subset, ElementDefinition superset, String path, ElementDefinition lDef, ElementDefinition rDef) throws FHIRFormatError, DefinitionException, IOException {
private boolean compareBindings(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, ElementDefinition subset, ElementDefinition superset, String path, ElementDefinition lDef, ElementDefinition rDef) throws FHIRFormatError, DefinitionException, IOException {
assert(lDef.hasBinding() || rDef.hasBinding());
if (!lDef.hasBinding()) {
subset.setBinding(rDef.getBinding());
@ -801,7 +847,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
}
// we can't really know about constraints. We create warnings, and collate them
private List<ElementDefinitionConstraintComponent> unionConstraints(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<ElementDefinitionConstraintComponent> left, List<ElementDefinitionConstraintComponent> right) {
private List<ElementDefinitionConstraintComponent> unionConstraints(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, List<ElementDefinitionConstraintComponent> left, List<ElementDefinitionConstraintComponent> right) {
List<ElementDefinitionConstraintComponent> result = new ArrayList<ElementDefinitionConstraintComponent>();
for (ElementDefinitionConstraintComponent l : left) {
boolean found = false;
@ -829,7 +875,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return result;
}
private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String url, String name, IWorkerContext ctxt) {
private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, String url, String name, IWorkerContext ctxt) {
StructureDefinition sd = ctxt.fetchResource(StructureDefinition.class, url);
if (sd == null) {
ValidationMessage vm = vmI(IssueSeverity.WARNING, "Unable to resolve profile "+url+" in profile "+name, path);
@ -841,7 +887,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return binding.getStrength() == BindingStrength.EXAMPLE || binding.getStrength() == BindingStrength.PREFERRED;
}
private ElementDefinitionBindingComponent unionBindings(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, ElementDefinitionBindingComponent left, ElementDefinitionBindingComponent right) throws FHIRFormatError, DefinitionException, IOException {
private ElementDefinitionBindingComponent unionBindings(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, ElementDefinitionBindingComponent left, ElementDefinitionBindingComponent right) throws FHIRFormatError, DefinitionException, IOException {
ElementDefinitionBindingComponent union = new ElementDefinitionBindingComponent();
if (left.getStrength().compareTo(right.getStrength()) < 0)
union.setStrength(left.getStrength());
@ -881,17 +927,17 @@ public class ProfileComparer extends CanonicalResourceComparer {
return gen.generate(model, prefix, 0, null);
}
private void genElementComp(String defPath, HierarchicalTableGenerator gen, List<Row> rows, StructuralMatch<ElementDefinition> combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException {
private void genElementComp(String defPath, HierarchicalTableGenerator gen, List<Row> rows, StructuralMatch<ElementDefinitionNode> combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException {
Row originalRow = slicingRow;
Row typesRow = null;
List<StructuralMatch<ElementDefinition>> children = combined.getChildren();
List<StructuralMatch<ElementDefinitionNode>> children = combined.getChildren();
Row row = gen.new Row();
rows.add(row);
String path = combined.either().getPath();
String path = combined.either().getDef().getPath();
row.setAnchor(path);
row.setColor(utilsRight.getRowColor(combined.either(), false));
row.setColor(utilsRight.getRowColor(combined.either().getDef(), false));
if (eitherHasSlicing(combined))
row.setLineColor(1);
else if (eitherHasSliceName(combined))
@ -917,7 +963,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE);
typesRow = row;
}
} else if (combined.either().hasContentReference())
} else if (combined.either().getDef().hasContentReference())
row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE);
else if (isPrimitive(combined))
row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
@ -927,7 +973,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
row.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
else
row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE);
String ref = defPath == null ? null : defPath + combined.either().getId();
String ref = defPath == null ? null : defPath + combined.either().getDef().getId();
String sName = tail(path);
String sn = getSliceName(combined);
if (sn != null)
@ -937,23 +983,23 @@ public class ProfileComparer extends CanonicalResourceComparer {
String leftColor = !combined.hasLeft() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
String rightColor = !combined.hasRight() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
if (combined.hasLeft()) {
nc = utilsRight.genElementNameCell(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
nc = utilsRight.genElementNameCell(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, false, ext, used , ref, sName);
} else {
nc = utilsRight.genElementNameCell(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
nc = utilsRight.genElementNameCell(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, false, ext, used , ref, sName);
}
if (combined.hasLeft()) {
frame(utilsRight.genElementCells(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName, nc, false), leftColor);
frame(utilsRight.genElementCells(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, true, ext, used , ref, sName, nc, false, false), leftColor);
} else {
frame(spacers(row, 4, gen), leftColor);
}
if (combined.hasRight()) {
frame(utilsRight.genElementCells(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used, ref, sName, nc, false), rightColor);
frame(utilsRight.genElementCells(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, true, ext, used, ref, sName, nc, false, false), rightColor);
} else {
frame(spacers(row, 4, gen), rightColor);
}
row.getCells().add(cellForMessages(gen, combined.getMessages()));
for (StructuralMatch<ElementDefinition> child : children) {
for (StructuralMatch<ElementDefinitionNode> child : children) {
genElementComp(defPath, gen, row.getSubRows(), child, corePath, prefix, originalRow, false);
}
}
@ -978,47 +1024,47 @@ public class ProfileComparer extends CanonicalResourceComparer {
return res;
}
private String getSliceName(StructuralMatch<ElementDefinition> combined) {
private String getSliceName(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return null;
}
private boolean isDataType(StructuralMatch<ElementDefinition> combined) {
private boolean isDataType(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean hasTarget(StructuralMatch<ElementDefinition> combined) {
private boolean hasTarget(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean isPrimitive(StructuralMatch<ElementDefinition> combined) {
private boolean isPrimitive(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean allAreReference(StructuralMatch<ElementDefinition> combined) {
private boolean allAreReference(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean hasChoice(StructuralMatch<ElementDefinition> combined) {
private boolean hasChoice(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean elementIsComplex(StructuralMatch<ElementDefinition> combined) {
private boolean elementIsComplex(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub velement.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue()
return false;
}
private boolean eitherHasSliceName(StructuralMatch<ElementDefinition> combined) {
private boolean eitherHasSliceName(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean eitherHasSlicing(StructuralMatch<ElementDefinition> combined) {
private boolean eitherHasSlicing(StructuralMatch<ElementDefinitionNode> combined) {
// TODO Auto-generated method stub
return false;
}

View File

@ -301,11 +301,11 @@ public class ResourceComparer {
private String halfColorForLevel(IssueSeverity level) {
switch (level) {
case ERROR:
return "#ffeeee";
return "#ffdddd";
case FATAL:
return "#ffcccc";
case WARNING:
return "#fff4ee";
return "#fff6ee";
default: // INFORMATION:
return "#fffff2";
}
@ -319,6 +319,9 @@ public class ResourceComparer {
XhtmlNode li = new XhtmlNode(NodeType.Element, "li");
piece.getChildren().add(li);
li.style("background-color: "+halfColorForLevel(msg.getLevel()));
if (msg.getLevel() == IssueSeverity.ERROR) {
li.style("font-weight: bold");
}
li.tx(msg.getMessage());
}
return cell;

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@ -113,5 +114,6 @@ public class StructuralMatch<T> {
return this;
}
}

View File

@ -36,6 +36,9 @@ import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -3504,7 +3507,7 @@ public class ProfileUtilities extends TranslatingUtilities {
List<TypeRefComponent> types = e.getType();
if (!e.hasType()) {
if (root) { // we'll use base instead of types then
StructureDefinition bsd = context.fetchResource(StructureDefinition.class, profile.getBaseDefinition());
StructureDefinition bsd = profile == null ? null : context.fetchResource(StructureDefinition.class, profile.getBaseDefinition());
if (bsd != null) {
if (bsd.hasUserData("path")) {
c.getPieces().add(gen.new Piece(Utilities.isAbsoluteUrl(bsd.getUserString("path")) ? bsd.getUserString("path") : imagePath +bsd.getUserString("path"), bsd.getName(), null));
@ -3586,7 +3589,7 @@ public class ProfileUtilities extends TranslatingUtilities {
c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null)));
}
ref = pkp.getLinkForProfile(profile, p.getValue());
ref = pkp == null ? null : pkp.getLinkForProfile(profile, p.getValue());
if (ref != null) {
String[] parts = ref.split("\\|");
if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) {
@ -3685,7 +3688,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private String checkPrepend(String corePath, String path) {
if (pkp.prependLinks() && !(path.startsWith("http:") || path.startsWith("https:")))
if (pkp != null && pkp.prependLinks() && !(path.startsWith("http:") || path.startsWith("https:")))
return corePath+path;
else
return path;
@ -4057,7 +4060,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (logicalModel && element.hasRepresentation(PropertyRepresentation.XMLATTR))
sName = "@"+sName;
Cell nc = genElementNameCell(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName);
genElementCells(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, nc, mustSupport);
genElementCells(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, nc, mustSupport, true);
if (element.hasSlicing()) {
if (standardExtensionSlicing(element)) {
used.used = true; // doesn't matter whether we have a type, we're used if we're setting up slicing ... element.hasType() && element.getType().get(0).hasProfile();
@ -4185,7 +4188,7 @@ public class ProfileUtilities extends TranslatingUtilities {
public List<Cell> genElementCells(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath,
String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef,
boolean ext, UnusedTracker used, String ref, String sName, Cell nameCell, boolean mustSupport) throws IOException {
boolean ext, UnusedTracker used, String ref, String sName, Cell nameCell, boolean mustSupport, boolean allowSubRows) throws IOException {
List<Cell> res = new ArrayList<>();
Cell gc = gen.new Cell();
row.getCells().add(gc);
@ -4211,7 +4214,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (extDefn == null) {
res.add(genCardinality(gen, element, row, hasDef, used, null));
res.add(addCell(row, gen.new Cell(null, null, "?gen-e1? "+element.getType().get(0).getProfile(), null, null)));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows));
} else {
String name = urltail(eurl);
nameCell.getPieces().get(0).setText(name);
@ -4224,7 +4227,7 @@ public class ProfileUtilities extends TranslatingUtilities {
else // if it's complex, we just call it nothing
// genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile);
res.add(addCell(row, gen.new Cell(null, null, "("+translate("sd.table", "Complex")+")", null, null)));
res.add(generateDescription(gen, row, element, extDefn.getElement(), used.used, null, extDefn.getUrl(), profile, corePath, imagePath, root, logicalModel, allInvariants, valueDefn, snapshot, mustSupport));
res.add(generateDescription(gen, row, element, extDefn.getElement(), used.used, null, extDefn.getUrl(), profile, corePath, imagePath, root, logicalModel, allInvariants, valueDefn, snapshot, mustSupport, allowSubRows));
}
} else {
res.add(genCardinality(gen, element, row, hasDef, used, null));
@ -4232,7 +4235,7 @@ public class ProfileUtilities extends TranslatingUtilities {
res.add(addCell(row, gen.new Cell()));
else
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows));
}
} else {
res.add(genCardinality(gen, element, row, hasDef, used, null));
@ -4240,7 +4243,7 @@ public class ProfileUtilities extends TranslatingUtilities {
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
else
res.add(addCell(row, gen.new Cell()));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows));
}
return res;
}
@ -4546,11 +4549,11 @@ public class ProfileUtilities extends TranslatingUtilities {
&& element.getSlicing().getRules() != SlicingRules.CLOSED && element.getSlicing().getDiscriminator().size() == 1 && element.getSlicing().getDiscriminator().get(0).getPath().equals("url") && element.getSlicing().getDiscriminator().get(0).getType().equals(DiscriminatorType.VALUE);
}
private Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, boolean snapshot, boolean mustSupportOnly) throws IOException, FHIRException {
return generateDescription(gen, row, definition, fallback, used, baseURL, url, profile, corePath, imagePath, root, logicalModel, allInvariants, null, snapshot, mustSupportOnly);
private Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows) throws IOException, FHIRException {
return generateDescription(gen, row, definition, fallback, used, baseURL, url, profile, corePath, imagePath, root, logicalModel, allInvariants, null, snapshot, mustSupportOnly, allowSubRows);
}
private Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, ElementDefinition valueDefn, boolean snapshot, boolean mustSupportOnly) throws IOException, FHIRException {
private Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, ElementDefinition valueDefn, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows) throws IOException, FHIRException {
Cell c = gen.new Cell();
row.getCells().add(c);
@ -4566,7 +4569,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
if (root) {
if (profile.getAbstract()) {
if (profile != null && profile.getAbstract()) {
if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.addPiece(gen.new Piece(null, "This is an abstract profile", null));
}
@ -4661,7 +4664,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (binding!=null && !binding.isEmpty()) {
if (!c.getPieces().isEmpty())
c.addPiece(gen.new Piece("br"));
BindingResolution br = pkp.resolveBinding(profile, binding, definition.getPath());
BindingResolution br = pkp == null ? makeNullBr(binding) : pkp.resolveBinding(profile, binding, definition.getPath());
c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, translate("sd.table", "Binding")+": ", null).addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(binding.getValueSetElement(), gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null)));
if (binding.hasStrength()) {
@ -4670,7 +4673,7 @@ public class ProfileUtilities extends TranslatingUtilities {
c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, ")", null)));
}
if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) {
br = pkp.resolveBinding(profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), definition.getPath());
br = pkp == null ? makeNullBr(binding) : pkp.resolveBinding(profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), definition.getPath());
c.addPiece(gen.new Piece("br"));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"extension-elementdefinition-maxvalueset.html", translate("sd.table", "Max Binding")+": ", "Max Value Set Extension").addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(binding, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null)));
@ -4706,7 +4709,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (definition.hasFixed()) {
if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, translate("sd.table", "Fixed Value")+": ", null).addStyle("font-weight:bold")));
if (!useTableForFixedValues || definition.getFixed().isPrimitive()) {
if (!useTableForFixedValues || !allowSubRows || definition.getFixed().isPrimitive()) {
String s = buildJson(definition.getFixed());
String link = null;
if (Utilities.isAbsoluteUrl(s))
@ -4714,7 +4717,7 @@ public class ProfileUtilities extends TranslatingUtilities {
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen")));
} else {
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "As shown", null).addStyle("color: darkgreen")));
genFixedValue(gen, row, definition.getFixed(), snapshot, false, corePath, false);
genFixedValue(gen, row, definition.getFixed(), snapshot, false, corePath, false);
}
if (isCoded(definition.getFixed()) && !hasDescription(definition.getFixed())) {
Piece p = describeCoded(gen, definition.getFixed());
@ -4724,7 +4727,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} else if (definition.hasPattern()) {
if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, translate("sd.table", "Required Pattern")+": ", null).addStyle("font-weight:bold")));
if (!useTableForFixedValues || definition.getPattern().isPrimitive())
if (!useTableForFixedValues || !allowSubRows || definition.getPattern().isPrimitive())
c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen")));
else {
c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, "At least the following", null).addStyle("color: darkgreen")));
@ -4764,6 +4767,13 @@ public class ProfileUtilities extends TranslatingUtilities {
return c;
}
private BindingResolution makeNullBr(ElementDefinitionBindingComponent binding) {
BindingResolution br = new BindingResolution();
br.url = "http://none.none/none";
br.display = "todo";
return br;
}
private ElementDefinitionBindingComponent makeUnifiedBinding(ElementDefinitionBindingComponent binding, ElementDefinition element) {
if (!element.hasUserData(DERIVATION_POINTER)) {
return binding;
@ -4804,7 +4814,7 @@ public class ProfileUtilities extends TranslatingUtilities {
ref = "?gen-fv?";
}
StructureDefinition sd = context.fetchTypeDefinition(value.fhirType());
for (org.hl7.fhir.r5.model.Property t : value.children()) {
if (t.getValues().size() > 0 || snapshot) {
ElementDefinition ed = findElementDefinition(sd, t.getName());

View File

@ -1142,7 +1142,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
}
}
CodeSystem cs = fetchResource(CodeSystem.class, inc.getSystem());
if (cs != null) {
if (cs != null && (cs.getContent() == CodeSystemContentMode.COMPLETE || cs.getContent() == CodeSystemContentMode.FRAGMENT)) {
pin.addParameter().setName("tx-resource").setResource(cs);
if (isTxCaching && cacheId == null || !cached.contains(cs.getVUrl())) {
cached.add(cs.getVUrl());

View File

@ -614,6 +614,9 @@ public class ExpressionNode {
public String check() {
if (kind == null) {
return "Error in expression - node has no kind";
}
switch (kind) {
case Name:
if (Utilities.noString(name))

View File

@ -628,6 +628,7 @@ public class ValueSetCheckerSimple extends ValueSetWorker implements ValueSetChe
break;
}
}
i = valueset.getCompose().getInclude().size();
for (ConceptSetComponent vsi : valueset.getCompose().getExclude()) {
Boolean nok = inComponent(vsi, i, system, code, valueset.getCompose().getInclude().size() == 1, warnings);
i++;

View File

@ -519,5 +519,8 @@ public class FHIRLexer {
public int getCurrentStart() {
return currentStart;
}
public String getSource() {
return source;
}
}

View File

@ -1000,7 +1000,9 @@ public class FHIRPathEngine {
wrapper.setProximal(proximal);
}
if (lexer.isConstant()) {
if (lexer.getCurrent() == null) {
throw lexer.error("Expression terminated unexpectedly");
} else if (lexer.isConstant()) {
boolean isString = lexer.isStringConstant();
if (!isString && (lexer.getCurrent().startsWith("-") || lexer.getCurrent().startsWith("+"))) {
// the grammar says that this is a unary operation; it affects the correct processing order of the inner operations

View File

@ -147,7 +147,10 @@ public class ResourceUtilities {
if (cc.hasCoding("http://unstats.un.org/unsd/methods/m49/m49.htm", "001")) {
return new Locale("en-US");
}
String c = cc.getCode("urn:iso:std:iso:3166:-2");
String c = cc.getCode("urn:iso:std:iso:3166");
if (c == null) {
return null;
}
String l = jl.get(c);
if (l == null) {
return null;

View File

@ -511,7 +511,7 @@ public class ToolingExtensions {
* @return The extension, if on this element, else null
*/
public static Extension getExtension(DomainResource resource, String name) {
if (name == null)
if (resource == null || name == null)
return null;
if (!resource.hasExtension())
return null;

View File

@ -1,6 +1,8 @@
package org.hl7.fhir.r5.utils.client.network;
import okhttp3.*;
import okio.Buffer;
import org.hl7.fhir.utilities.ToolingClientLogger;
import javax.annotation.Nonnull;
@ -26,8 +28,17 @@ public class FhirLoggingInterceptor implements Interceptor {
public Response intercept(@Nonnull Interceptor.Chain chain) throws IOException {
// Log Request
Request request = chain.request();
logger.logRequest(request.method(), request.url().toString(), new ArrayList<>(request.headers().names()),
request.body() != null ? request.body().toString().getBytes() : null);
List<String> hdrs = new ArrayList<>();
for (String s : request.headers().toString().split("\\n")) {
hdrs.add(s.trim());
}
byte[] cnt = null;
if (request.body() != null) {
Buffer buf = new Buffer();
request.body().writeTo(buf);
cnt = buf.readByteArray();
}
logger.logRequest(request.method(), request.url().toString(), hdrs, cnt);
// Log Response
Response response = null;

View File

@ -110,7 +110,7 @@ public class SimpleHTTPClient {
public HTTPResult get(String url, String accept) throws IOException {
URL u = new URL(url);
boolean isSSL = url.startsWith("https://");
// boolean isSSL = url.startsWith("https://");
// handling redirects - setInstanceFollowRedirects(true) doesn't handle crossing http to https

View File

@ -649,7 +649,7 @@ public class Utilities {
StringBuilder s = new StringBuilder();
boolean d = false;
for (String arg : args) {
if (args != null) {
if (arg != null) {
if (!d)
d = !noString(arg);
else if (s.toString() != null && !s.toString().endsWith("/") && !arg.startsWith("/"))
@ -660,14 +660,6 @@ public class Utilities {
return s.toString();
}
// public static void checkCase(String filename) {
// File f = new CSFile(filename);
// if (!f.getName().equals(filename))
// throw new FHIRException("Filename ")
//
// }
public static String nmtokenize(String cs) {
if (cs == null)
return "";

View File

@ -246,7 +246,7 @@ All_observations_should_have_a_performer = All observations should have a perfor
All_observations_should_have_a_subject = All observations should have a subject
Unable_to_resolve_slice_matching__no_fixed_value_or_required_value_set = Unable to resolve slice matching - no fixed value or required value set
Unable_to_resolve_slice_matching__slice_matching_by_value_set_not_done = Unable to resolve slice matching - slice matching by value set not done
Problem_processing_expression__in_profile__path__ = Problem processing expression {0} in profile {1} path {2}: {3}
Problem_processing_expression__in_profile__path__ = Problem processing expression ''{0}'' in profile ''{1}'' at path ''{2}'': {3}
Unable_to_find_element_with_id_ = Unable to find element with id ''{0}''
Slice_encountered_midway_through_set_path___id___ = Slice encountered midway through set (path = {0}, id = {1}); {2}
Unable_to_resolve_actual_type_ = Unable to resolve actual type {0}

View File

@ -54,6 +54,10 @@
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -167,6 +167,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark</artifactId>
<optional>true</optional>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>

View File

@ -5490,7 +5490,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
try {
n = fpe.parse(fixExpr(inv.getExpression(), inv.getKey()));
} catch (FHIRLexerException e) {
throw new FHIRException(context.formatMessage(I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, inv.getExpression(), profile.getUrl(), path, e.getMessage()));
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, false, I18nConstants.PROBLEM_PROCESSING_EXPRESSION__IN_PROFILE__PATH__, inv.getExpression(), profile.getUrl(), path, e.getMessage());
return;
}
timeTracker.fpe(t);
inv.setUserData("validator.expression.cache", n);

View File

@ -19,7 +19,7 @@
<properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.86</validator_test_case_version>
<validator_test_case_version>1.1.87-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.7.1</junit_jupiter_version>
<junit_platform_launcher_version>1.7.1</junit_platform_launcher_version>
<maven_surefire_version>3.0.0-M5</maven_surefire_version>