Merge branch 'master' into tx-server-cache-analysis

This commit is contained in:
dotasek 2022-01-18 16:10:21 -05:00
commit 0a3e9d3f31
45 changed files with 770 additions and 199 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

@ -170,6 +170,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

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

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

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

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

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

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

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

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

@ -1156,7 +1156,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

@ -3,34 +3,34 @@ package org.hl7.fhir.r5.formats;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
@ -63,6 +63,7 @@ POSSIBILITY OF SUCH DAMAGE.
*/
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.net.URI;
@ -117,25 +118,31 @@ public abstract class FormatUtilities {
}
public static ParserBase makeParser(FhirFormat format) {
switch (format) {
case XML : return new XmlParser();
case JSON : return new JsonParser();
case TURTLE : throw new Error("unsupported Format "+format.toString()); // return new TurtleParser();
case VBAR : throw new Error("unsupported Format "+format.toString()); //
case TEXT : throw new Error("unsupported Format "+format.toString()); //
}
throw new Error("unsupported Format "+format.toString());
return makeParser(format.name());
}
public static ParserBase makeParser(String format) {
if ("XML".equalsIgnoreCase(format)) return new XmlParser();
if ("JSON".equalsIgnoreCase(format)) return new JsonParser();
if ("TURTLE".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); // return new TurtleParser();
if ("JSONLD".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); // return new JsonLdParser();
if ("VBAR".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); //
if ("TEXT".equalsIgnoreCase(format)) throw new Error("unsupported Format "+format.toString()); //
throw new Error("unsupported Format "+format);
}
/*
* Note: Use fully qualified references to the parsers here in order to avoid adding
* a class-level import statement for them. This is because the
* XmlParser and JsonParser are huuuuuge classes and classloading them is quite expensive
* in cases where they won't actually ever be instantiated (such as when using the
* validator in HAPI FHIR).
*
* See https://github.com/hapifhir/hapi-fhir/issues/3268
*/
if ("XML".equalsIgnoreCase(format))
return new org.hl7.fhir.r5.formats.XmlParser();
if ("JSON".equalsIgnoreCase(format))
return new org.hl7.fhir.r5.formats.JsonParser();
if ("TURTLE".equalsIgnoreCase(format))
throw new Error("unsupported Format " + format.toString()); // return new TurtleParser();
if ("JSONLD".equalsIgnoreCase(format))
throw new Error("unsupported Format " + format.toString()); // return new JsonLdParser();
if ("VBAR".equalsIgnoreCase(format)) throw new Error("unsupported Format " + format.toString()); //
if ("TEXT".equalsIgnoreCase(format)) throw new Error("unsupported Format " + format.toString()); //
throw new Error("unsupported Format " + format);
}
public static FhirFormat determineFormat(byte[] source) throws FHIRException {
return determineFormat(source, MAX_SCAN_LENGTH);

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

@ -175,7 +175,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
hierarchy = hierarchy || csNav.isRestructure();
List<String> langs = new ArrayList<>();
addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, false), maps);
addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, definitions, commentS, version, deprecated, properties, null, null, false), maps);
for (ConceptDefinitionComponent c : csNav.getConcepts(null)) {
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, definitions, commentS, version, deprecated, maps, cs.getUrl(), cs, properties, csNav, langs, isSupplement) || hasExtensions;
}

View File

@ -20,6 +20,7 @@ import org.hl7.fhir.r5.model.Narrative;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.model.Reference;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
@ -488,4 +489,16 @@ public abstract class ResourceRenderer extends DataRenderer {
private String getPrimitiveValue(ResourceWrapper r, String name) throws UnsupportedEncodingException, FHIRException, IOException {
return r.has(name) && r.getChildByName(name).hasValues() ? r.getChildByName(name).getValues().get(0).getBase().primitiveValue() : null;
}
public void renderOrError(DomainResource dr) {
try {
render(dr);
} catch (Exception e) {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.para().tx("Error rendering: "+e.getMessage());
dr.setText(null);
inject(dr, x, NarrativeStatus.GENERATED);
}
}
}

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRFormatError;
@ -201,7 +202,7 @@ public abstract class TerminologyRenderer extends ResourceRenderer {
return null;
}
protected XhtmlNode addTableHeaderRowStandard(XhtmlNode t, boolean hasHierarchy, boolean hasDisplay, boolean definitions, boolean comments, boolean version, boolean deprecated, List<PropertyComponent> properties, List<String> langs, boolean doLangs) {
protected XhtmlNode addTableHeaderRowStandard(XhtmlNode t, boolean hasHierarchy, boolean hasDisplay, boolean definitions, boolean comments, boolean version, boolean deprecated, List<PropertyComponent> properties, List<String> langs, Map<String, String> designations, boolean doDesignations) {
XhtmlNode tr = t.tr();
if (hasHierarchy) {
tr.td().b().tx("Lvl");
@ -234,7 +235,10 @@ public abstract class TerminologyRenderer extends ResourceRenderer {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", display, getContext().getLang()));
}
}
if (doLangs) {
if (doDesignations) {
for (String url : designations.keySet()) {
tr.td().b().addText(designations.get(url));
}
for (String lang : langs) {
tr.td().b().addText(describeLang(lang));
}

View File

@ -29,6 +29,7 @@ import org.hl7.fhir.r5.model.ConceptMap;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Enumerations.FilterOperator;
import org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.ExtensionHelper;
import org.hl7.fhir.r5.model.PrimitiveType;
@ -39,6 +40,7 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
@ -48,7 +50,11 @@ import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Title;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
@ -65,7 +71,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
private static final String ABSTRACT_CODE_HINT = "This code is not selectable ('Abstract')";
private static final int MAX_LANGS_IN_LINE = 5;
private static final int MAX_DESIGNATIONS_IN_LINE = 5;
private List<ConceptMapRenderInstructions> renderingMaps = new ArrayList<ConceptMapRenderInstructions>();
@ -222,7 +228,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
doLangs = false;
} else {
// if we're not doing definitions and we don't have too many languages, we'll do them in line
if (langs.size() < MAX_LANGS_IN_LINE) {
if (langs.size() < MAX_DESIGNATIONS_IN_LINE) {
doLangs = true;
if (vs.hasLanguage()) {
tdDisp.tx(" - "+describeLang(vs.getLanguage()));
@ -586,8 +592,12 @@ public class ValueSetRenderer extends TerminologyRenderer {
private boolean checkDoDefinition(List<ValueSetExpansionContainsComponent> contains) {
for (ValueSetExpansionContainsComponent c : contains) {
CodeSystem cs = getContext().getWorker().fetchCodeSystem(c.getSystem());
if (cs != null)
return true;
if (cs != null) {
ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(cs, c.getCode());
if (cd != null && cd.hasDefinition()) {
return true;
}
}
if (checkDoDefinition(c.getContains()))
return true;
}
@ -754,13 +764,14 @@ public class ValueSetRenderer extends TerminologyRenderer {
private boolean generateComposition(XhtmlNode x, ValueSet vs, boolean header, List<UsedConceptMap> maps) throws FHIRException, IOException {
boolean hasExtensions = false;
List<String> langs = new ArrayList<String>();
Map<String, String> designations = new HashMap<>(); // map of url = description, where url is the designation code. Designations that are for languages won't make it into this list
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
scanForLangs(inc, langs);
scanDesignations(inc, langs, designations);
}
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
scanForLangs(inc, langs);
scanDesignations(inc, langs, designations);
}
boolean doLangs = langs.size() < MAX_LANGS_IN_LINE;
boolean doDesignations = langs.size() + designations.size() < MAX_DESIGNATIONS_IN_LINE;
if (header) {
XhtmlNode h = x.h2();
@ -769,35 +780,48 @@ public class ValueSetRenderer extends TerminologyRenderer {
if (vs.hasCopyrightElement())
generateCopyright(x, vs);
}
int index = 0;
if (vs.getCompose().getInclude().size() == 1 && vs.getCompose().getExclude().size() == 0) {
hasExtensions = genInclude(x.ul(), vs.getCompose().getInclude().get(0), "Include", langs, doLangs, maps) || hasExtensions;
hasExtensions = genInclude(x.ul(), vs.getCompose().getInclude().get(0), "Include", langs, doDesignations, maps, designations, index) || hasExtensions;
} else {
XhtmlNode p = x.para();
p.tx("This value set includes codes based on the following rules:");
XhtmlNode ul = x.ul();
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
hasExtensions = genInclude(ul, inc, "Include", langs, doLangs, maps) || hasExtensions;
hasExtensions = genInclude(ul, inc, "Include", langs, doDesignations, maps, designations, index) || hasExtensions;
index++;
}
if (vs.getCompose().hasExclude()) {
p = x.para();
p.tx("This value set excludes codes based on the following rules:");
ul = x.ul();
for (ConceptSetComponent exc : vs.getCompose().getExclude()) {
hasExtensions = genInclude(ul, exc, "Exclude", langs, doLangs, maps) || hasExtensions;
hasExtensions = genInclude(ul, exc, "Exclude", langs, doDesignations, maps, designations, index) || hasExtensions;
index++;
}
}
}
// now, build observed languages
if (!doLangs && langs.size() > 0) {
if (!doDesignations && langs.size() + designations.size() > 0) {
Collections.sort(langs);
x.para().b().tx("Additional Language Displays");
XhtmlNode t = x.table( "codes");
if (designations.size() == 0) {
x.para().b().tx("Additional Language Displays");
} else if (langs.size() == 0) {
x.para().b().tx("Additional Designations");
} else {
x.para().b().tx("Additional Designations and Language Displays");
}
XhtmlNode t = x.table("codes");
XhtmlNode tr = t.tr();
tr.td().b().tx("Code");
for (String lang : langs)
for (String url : designations.keySet()) {
tr.td().b().addText(designations.get(url));
}
for (String lang : langs) {
tr.td().b().addText(describeLang(lang));
}
for (ConceptSetComponent c : vs.getCompose().getInclude()) {
for (ConceptReferenceComponent cc : c.getConcept()) {
addLanguageRow(cc, t, langs);
@ -805,10 +829,102 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
}
return hasExtensions;
}
private void scanForLangs(ConceptSetComponent inc, List<String> langs) {
private void renderExpansionRules(XhtmlNode x, ConceptSetComponent inc, int index, Map<String, ConceptDefinitionComponent> definitions) throws FHIRException, IOException {
String s = "This include specifies a heirarchy for when value sets are generated for use in a User Interface, but the rules are not properly defined";
if (inc.hasExtension(ToolingExtensions.EXT_EXPAND_RULES)) {
String rule = inc.getExtensionString(ToolingExtensions.EXT_EXPAND_RULES);
if (rule != null) {
switch (rule) {
case "all-codes": s = "This include specifies a heirarchy for when value sets are generated for use in a User Interface. The expansion contains all the codes, and also this structure:";
case "ungrouped": s = "This include specifies a heirarchy for when value sets are generated for use in a User Interface. The expansion contains this structure, and any codes not found in the structure:";
case "groups-only": s = "This include specifies a heirarchy for when value sets are generated for use in a User Interface. The expansion contains this structure:";
}
}
}
x.br();
x.tx(s);
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context.getDestDir(), context.isInlineGraphics(), true);
TableModel model = gen.new TableModel("exp.h="+index, !forResource);
model.setAlternating(true);
model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("vs.exp.header", "Code"), translate("vs.exp.hint", "The code for the item"), null, 0));
model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("vs.exp.header", "Display"), translate("vs.exp.hint", "The display for the item"), null, 0));
for (Extension ext : inc.getExtensionsByUrl(ToolingExtensions.EXT_EXPAND_GROUP)) {
renderExpandGroup(gen, model, ext, inc, definitions);
}
x.br();
x.tx("table");
XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null);
x.getChildNodes().add(xn);
}
private void renderExpandGroup(HierarchicalTableGenerator gen, TableModel model, Extension ext, ConceptSetComponent inc, Map<String, ConceptDefinitionComponent> definitions) {
Row row = gen.new Row();
model.getRows().add(row);
row.setIcon("icon_entry_blue.png", "entry");
String code = ext.getExtensionString("code");
if (code != null) {
row.getCells().add(gen.new Cell(null, null, code, null, null));
row.getCells().add(gen.new Cell(null, null, getDisplayForCode(inc, code, definitions), null, null));
} else if (ext.hasId()) {
row.getCells().add(gen.new Cell(null, null, "(#"+ext.getId()+")", null, null));
row.getCells().add(gen.new Cell(null, null, ext.getExtensionString("display"), null, null));
} else {
row.getCells().add(gen.new Cell(null, null, null, null, null));
row.getCells().add(gen.new Cell(null, null, ext.getExtensionString("display"), null, null));
}
for (Extension member : ext.getExtensionsByUrl("member")) {
Row subRow = gen.new Row();
row.getSubRows().add(subRow);
subRow.setIcon("icon_entry_blue.png", "entry");
String mc = member.getValue().primitiveValue();
// mc might be a reference to another expansion group - we check that first, or to a code in the compose
if (mc.startsWith("#")) {
// it's a reference by id
subRow.getCells().add(gen.new Cell(null, null, "("+mc+")", null, null));
subRow.getCells().add(gen.new Cell(null, null, "group reference by id", null, null));
} else {
Extension tgt = findTargetByCode(inc, mc);
if (tgt != null) {
subRow.getCells().add(gen.new Cell(null, null, mc, null, null));
subRow.getCells().add(gen.new Cell(null, null, "group reference by code", null, null));
} else {
subRow.getCells().add(gen.new Cell(null, null, mc, null, null));
subRow.getCells().add(gen.new Cell(null, null, getDisplayForCode(inc, mc, definitions), null, null));
}
}
}
}
private Extension findTargetByCode(ConceptSetComponent inc, String mc) {
for (Extension ext : inc.getExtensionsByUrl(ToolingExtensions.EXT_EXPAND_GROUP)) {
String code = ext.getExtensionString("code");
if (mc.equals(code)) {
return ext;
}
}
return null;
}
private String getDisplayForCode(ConceptSetComponent inc, String code, Map<String, ConceptDefinitionComponent> definitions) {
for (ConceptReferenceComponent cc : inc.getConcept()) {
if (code.equals(cc.getCode())) {
if (cc.hasDisplay()) {
return cc.getDisplay();
}
}
}
if (definitions.containsKey(code)) {
return definitions.get(code).getDisplay();
}
return null;
}
private void scanDesignations(ConceptSetComponent inc, List<String> langs, Map<String, String> designations) {
for (ConceptReferenceComponent cc : inc.getConcept()) {
for (Extension ext : cc.getExtension()) {
if (ToolingExtensions.EXT_TRANSLATION.equals(ext.getUrl())) {
@ -822,17 +938,47 @@ public class ValueSetRenderer extends TerminologyRenderer {
String lang = d.getLanguage();
if (!Utilities.noString(lang) && !langs.contains(lang)) {
langs.add(lang);
} else {
// can we present this as a designation that we know?
String url = getUrlForDesignation(d);
String disp = getDisplayForUrl(url);
if (disp != null && !designations.containsKey(url)) {
designations.put(url, disp);
}
}
}
}
}
private boolean genInclude(XhtmlNode ul, ConceptSetComponent inc, String type, List<String> langs, boolean doLangs, List<UsedConceptMap> maps) throws FHIRException, IOException {
private String getDisplayForUrl(String url) {
if (url == null) {
return null;
}
switch (url) {
case "http://snomed.info/sct#900000000000003001":
return "Fully specified name";
case "http://snomed.info/sct#900000000000013009":
return "Synonym";
default:
return null;
}
}
private String getUrlForDesignation(ConceptReferenceDesignationComponent d) {
if (d.hasUse() && d.getUse().hasSystem() && d.getUse().hasCode()) {
return d.getUse().getSystem()+"#"+d.getUse().getCode();
} else {
return null;
}
}
private boolean genInclude(XhtmlNode ul, ConceptSetComponent inc, String type, List<String> langs, boolean doDesignations, List<UsedConceptMap> maps, Map<String, String> designations, int index) throws FHIRException, IOException {
boolean hasExtensions = false;
XhtmlNode li;
li = ul.li();
CodeSystem e = getContext().getWorker().fetchCodeSystem(inc.getSystem());
Map<String, ConceptDefinitionComponent> definitions = new HashMap<>();
if (inc.hasSystem()) {
if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) {
li.addText(type+" all codes defined in ");
@ -847,7 +993,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
// for performance reasons, we do all the fetching in one batch
Map<String, ConceptDefinitionComponent> definitions = getConceptsForCodes(e, inc);
definitions = getConceptsForCodes(e, inc);
XhtmlNode t = li.table("none");
boolean hasComments = false;
@ -859,7 +1005,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
}
if (hasComments || hasDefinition)
hasExtensions = true;
addMapHeaders(addTableHeaderRowStandard(t, false, true, hasDefinition, hasComments, false, false, null, langs, doLangs), maps);
addMapHeaders(addTableHeaderRowStandard(t, false, true, hasDefinition, hasComments, false, false, null, langs, designations, doDesignations), maps);
for (ConceptReferenceComponent c : inc.getConcept()) {
XhtmlNode tr = t.tr();
XhtmlNode td = tr.td();
@ -886,7 +1032,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
smartAddText(td, "Note: "+ToolingExtensions.readStringExtension(c, ToolingExtensions.EXT_VS_COMMENT));
}
}
if (doLangs) {
if (doDesignations) {
addDesignationsToRow(c, designations, tr);
addLangaugesToRow(c, langs, tr);
}
}
@ -946,6 +1093,10 @@ public class ValueSetRenderer extends TerminologyRenderer {
AddVsRef(vs.asStringValue(), li);
}
}
if (inc.hasExtension(ToolingExtensions.EXT_EXPAND_RULES) || inc.hasExtension(ToolingExtensions.EXT_EXPAND_GROUP)) {
hasExtensions = true;
renderExpansionRules(li, inc, index, definitions);
}
} else {
li.tx("Import all the codes that are contained in ");
if (inc.getValueSet().size() < 4) {
@ -968,6 +1119,20 @@ public class ValueSetRenderer extends TerminologyRenderer {
return hasExtensions;
}
public void addDesignationsToRow(ConceptReferenceComponent c, Map<String, String> designations, XhtmlNode tr) {
for (String url : designations.keySet()) {
String d = null;
if (d == null) {
for (ConceptReferenceDesignationComponent dd : c.getDesignation()) {
if (url.equals(getUrlForDesignation(dd))) {
d = dd.getValue();
}
}
}
tr.td().addText(d == null ? "" : d);
}
}
public void addLangaugesToRow(ConceptReferenceComponent c, List<String> langs, XhtmlNode tr) {
for (String lang : langs) {
String d = null;

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

@ -80,14 +80,14 @@ public class NPMPackageGenerator {
private String getDirectory() {
switch (this) {
case RESOURCE: return "package/";
case EXAMPLE: return "example/";
case OPENAPI: return "openapi/";
case SCHEMATRON: return "xml/";
case RDF: return "rdf/";
case OTHER: return "other/";
case TEMPLATE: return "other/";
case JEKYLL: return "jekyll/";
case TOOL: return "bin/";
case EXAMPLE: return "package/example/";
case OPENAPI: return "package/openapi/";
case SCHEMATRON: return "package/xml/";
case RDF: return "package/rdf/";
case OTHER: return "package/other/";
case TEMPLATE: return "package/other/";
case JEKYLL: return "package/jekyll/";
case TOOL: return "package/bin/";
}
return "/";
}
@ -323,7 +323,7 @@ public class NPMPackageGenerator {
public void addFile(Category cat, String name, byte[] content) throws IOException {
String path = cat.getDirectory()+name;
if (path.length() > 100) {
name = name.substring(0, name.indexOf("-"))+"-"+UUID.randomUUID().toString();
name = name.substring(0, name.indexOf("-"))+"-"+UUID.randomUUID().toString()+".json";
path = cat.getDirectory()+name;
}

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

@ -198,6 +198,8 @@ public class ToolingExtensions {
public static final String EXT_TARGET_ID = "http://hl7.org/fhir/StructureDefinition/targetElement";
public static final String EXT_TARGET_PATH = "http://hl7.org/fhir/StructureDefinition/targetPath";
public static final String EXT_VALUESET_SYSTEM = "http://hl7.org/fhir/StructureDefinition/valueset-system";
public static final String EXT_EXPAND_RULES = "http://hl7.org/fhir/StructureDefinition/valueset-expand-rules";
public static final String EXT_EXPAND_GROUP = "http://hl7.org/fhir/StructureDefinition/valueset-expand-group";
// specific extension helpers
@ -511,7 +513,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

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

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

@ -134,7 +134,7 @@ public class VersionUtilities {
}
public static String listSupportedVersions() {
return "1.0.2, 1.4.0, 3.0.2, 4.0.1, 4.1.0, 4.3.0, 5.0, "+CURRENT_FULL_VERSION;
return "1.0.2, 1.4.0, 3.0.2, 4.0.1, 4.1.0, 4.3.0, 5.0, " + CURRENT_FULL_VERSION;
}
public static boolean isR5Ver(String ver) {

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

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -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

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -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>
@ -228,6 +235,24 @@
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven_surefire_version}</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes combine.children="override">
<exclude>org/hl7/fhir/validation/cli/services/ValidationServiceTest.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>

View File

@ -588,7 +588,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
private void handleOutputToStream(Resource r, String fn, OutputStream s, String version) throws FHIRException, IOException {
if (fn.endsWith(".html") || fn.endsWith(".htm") && r instanceof DomainResource)
new XhtmlComposer(XhtmlComposer.HTML, true).compose(s, ((DomainResource) r).getText().getDiv());
else if (version.startsWith("3.0")) {
else if (VersionUtilities.isR3Ver(version)) {
org.hl7.fhir.dstu3.model.Resource res = VersionConvertorFactory_30_50.convertResource(r);
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
new org.hl7.fhir.dstu3.formats.XmlParser().setOutputStyle(org.hl7.fhir.dstu3.formats.IParser.OutputStyle.PRETTY).compose(s, res);
@ -598,7 +598,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
TextFile.stringToStream(org.hl7.fhir.dstu3.utils.StructureMapUtilities.render((org.hl7.fhir.dstu3.model.StructureMap) res), s, false);
else
throw new FHIRException("Unsupported format for " + fn);
} else if (version.startsWith("4.0")) {
} else if (VersionUtilities.isR4Ver(version)) {
org.hl7.fhir.r4.model.Resource res = VersionConvertorFactory_40_50.convertResource(r);
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
new org.hl7.fhir.r4.formats.XmlParser().setOutputStyle(org.hl7.fhir.r4.formats.IParser.OutputStyle.PRETTY).compose(s, res);
@ -608,7 +608,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
TextFile.stringToStream(org.hl7.fhir.r4.utils.StructureMapUtilities.render((org.hl7.fhir.r4.model.StructureMap) res), s, false);
else
throw new FHIRException("Unsupported format for " + fn);
} else if (version.startsWith("1.4")) {
} else if (VersionUtilities.isR2BVer(version)) {
org.hl7.fhir.dstu2016may.model.Resource res = VersionConvertorFactory_14_50.convertResource(r);
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
new org.hl7.fhir.dstu2016may.formats.XmlParser().setOutputStyle(org.hl7.fhir.dstu2016may.formats.IParser.OutputStyle.PRETTY).compose(s, res);
@ -616,7 +616,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
new org.hl7.fhir.dstu2016may.formats.JsonParser().setOutputStyle(org.hl7.fhir.dstu2016may.formats.IParser.OutputStyle.PRETTY).compose(s, res);
else
throw new FHIRException("Unsupported format for " + fn);
} else if (version.startsWith("1.0")) {
} else if (VersionUtilities.isR2Ver(version)) {
org.hl7.fhir.dstu2.model.Resource res = VersionConvertorFactory_10_50.convertResource(r, new org.hl7.fhir.convertors.misc.IGR2ConvertorAdvisor5());
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
new org.hl7.fhir.dstu2.formats.JsonParser().setOutputStyle(org.hl7.fhir.dstu2.formats.IParser.OutputStyle.PRETTY).compose(s, res);
@ -624,7 +624,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
new org.hl7.fhir.dstu2.formats.JsonParser().setOutputStyle(org.hl7.fhir.dstu2.formats.IParser.OutputStyle.PRETTY).compose(s, res);
else
throw new FHIRException("Unsupported format for " + fn);
} else if (version.equals(Constants.VERSION)) {
} else if (VersionUtilities.isR5Ver(version)) {
if (fn.endsWith(".xml") && !fn.endsWith("template.xml"))
new XmlParser().setOutputStyle(org.hl7.fhir.r5.formats.IParser.OutputStyle.PRETTY).compose(s, r);
else if (fn.endsWith(".json") && !fn.endsWith("template.json"))

View File

@ -2,12 +2,16 @@ package org.hl7.fhir.validation.cli.utils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.ToolsVersion;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Map;
/**
* Class for displaying output to the cli user.
@ -16,6 +20,7 @@ import java.io.InputStream;
*/
public class Display {
private static String toMB(long maxMemory) {
return Long.toString(maxMemory / (1024 * 1024));
}
@ -29,6 +34,29 @@ public class Display {
System.out.println();
}
final static String CURLY_START = "\\{\\{";
final static String CURLY_END = "\\}\\}";
final static String getMoustacheString(final String string) {
return CURLY_START + string + CURLY_END;
}
final static String[][] PLACEHOLDERS = {
{ getMoustacheString("XML_AND_JSON_FHIR_VERSIONS"), "1.0, 1.4, 3.0, 4.0," + Constants.VERSION_MM },
{ getMoustacheString("TURTLE_FHIR_VERSIONS"), "3.0, 4.0, " + Constants.VERSION_MM },
{ getMoustacheString("FHIR_MAJOR_VERSIONS"), "1.0|1.4|3.0|" + VersionUtilities.CURRENT_VERSION},
{ getMoustacheString("FHIR_MINOR_VERSIONS"), "1.0.2|1.4.0|3.0.2|4.0.1|" + VersionUtilities.CURRENT_FULL_VERSION },
{ getMoustacheString("FHIR_CURRENT_VERSION"), VersionUtilities.CURRENT_VERSION},
};
final static String replacePlaceholders(final String input, final String[][] placeholders) {
String output = input;
for (String[] placeholder : placeholders) {
output = output.replaceAll(placeholder[0], placeholder[1]);
}
return output;
}
/**
* Loads the help details from resources/help.txt, and displays them on the command line to the user.
*/
@ -37,12 +65,15 @@ public class Display {
InputStream help = classLoader.getResourceAsStream("help.txt");
try {
String data = IOUtils.toString(help, "UTF-8");
System.out.println(data);
System.out.println(replacePlaceholders(data, PLACEHOLDERS));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Prints out system info to the command line.
*/

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

@ -6,8 +6,8 @@ command line
The FHIR validation tool validates a FHIR resource or bundle.
Schema and schematron checking is performed, then some additional checks are performed.
* XML & Json (FHIR versions 1.0, 1.4, 3.0, 4.0, " + Constants.VERSION_MM + ")
* Turtle (FHIR versions 3.0, 4.0, " + Constants.VERSION_MM + ")
* XML & Json (FHIR versions {{XML_AND_JSON_FHIR_VERSIONS}})
* Turtle (FHIR versions {{TURTLE_FHIR_VERSIONS}})
If requested, instances will also be verified against the appropriate schema
W3C XML Schema, JSON schema or ShEx, as appropriate
@ -22,8 +22,8 @@ The following parameters are supported:
Patterns are limited to a directory followed by a filename with an embedded
asterisk. E.g. foo*-examples.xml or someresource.*, etc.
-version [ver]: The FHIR version to use. This can only appear once.
valid values 1.0 | 1.4 | 3.0 | " + VersionUtilities.CURRENT_VERSION + " or 1.0.2 | 1.4.0 | 3.0.2 | 4.0.1 | " + VersionUtilities.CURRENT_FULL_VERSION);
Default value is " + VersionUtilities.CURRENT_VERSION);
valid values {{FHIR_MAJOR_VERSIONS}} or {{FHIR_MINOR_VERSIONS}}
Default value is {{FHIR_CURRENT_VERSION}}
-ig [package|file|folder|url]: an IG or profile definition to load. Can be
the URL of an implementation guide or a package ([id]-[ver]) for
a built implementation guide or a local folder that contains a
@ -48,7 +48,7 @@ The following parameters are supported:
-showReferenceMessages
Includes validation messages resulting from validating target resources
against profiles defined on a reference. This increases the volume of
validationmessages, but may allow easier debugging. If not specified,
validation messages, but may allow easier debugging. If not specified,
then only a high-level message indicating that the referenced item wasn't
valid against the listed profile(s) will be provided.
-questionnaire mode: what to do with when validating QuestionnaireResponse resources

View File

@ -0,0 +1,58 @@
package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.validation.cli.utils.Display;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import static org.junit.jupiter.api.Assertions.*;
public class DisplayTests {
@Test
@DisplayName("Check for placeholder replacement in help output")
public void displayHelpDetails() {
final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
final PrintStream originalOut = System.out;
final PrintStream originalErr = System.err;
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
try {
Display.displayHelpDetails();
String output = outContent.toString();
for (String[] placeHolder: Display.PLACEHOLDERS) {
assertTrue(output.contains(placeHolder[1]), placeHolder[1] + " is not contained in output:\n" + output);
assertFalse(output.contains(placeHolder[0]), placeHolder[0] + " found in output:\n" + output);
}
}
finally {
System.setOut(originalOut);
System.setErr(originalErr);
}
}
@Test
@DisplayName("Test replacePlaceholder base case")
public void testReplacePlaceholdersBaseCase() {
final String myTestString = "The {{DUMMY_A}} jumps over the {{DUMMY_B}}.";
final String[][] placeHolders = {
{ "\\{\\{DUMMY_A\\}\\}", "quick brown fox"},
{ "\\{\\{DUMMY_B\\}\\}", "lazy dog"},
};
final String expectedOutput = "The quick brown fox jumps over the lazy dog.";
final String output = Display.replacePlaceholders(myTestString, placeHolders);
assertEquals(expectedOutput, output);
}
}

View File

@ -14,12 +14,12 @@
HAPI FHIR
-->
<artifactId>org.hl7.fhir.core</artifactId>
<version>5.6.23-SNAPSHOT</version>
<version>5.6.26-SNAPSHOT</version>
<packaging>pom</packaging>
<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</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>