Fix issue with comparer not rendering properly and add explicit checks around cardinality

This commit is contained in:
Grahame Grieve 2022-01-12 17:43:39 +11:00
parent 73737b5b4c
commit ecad7cc5f8
9 changed files with 287 additions and 61 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

@ -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

@ -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:\r\n \""+left.current().getMustSupport()+"\"\r\n \""+right.current().getMustSupport()+"\"", path, comp.getMessages(), res.getMessages());
}
subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport());
@ -198,11 +212,16 @@ 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()));
@ -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) {
@ -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)
@ -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:\r\n \""+leftMin+"\"\r\n vs \""+rightMin+"\"", path, comp.getMessages(), res.getMessages());
} else if (rightMin == 0) {
vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ:\r\n \""+leftMin+"\"\r\n vs \""+rightMin+"\"", path, comp.getMessages(), res.getMessages());
} else {
vm(IssueSeverity.INFORMATION, "Element minimum cardinalities differ:\r\n \""+leftMin+"\"\r\n vs \""+rightMin+"\"", path, comp.getMessages(), res.getMessages());
}
}
if (leftMax != rightMax) {
if (leftMax == Integer.MAX_VALUE) {
vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ:\r\n \""+leftMax+"\"\r\n vs \""+rightMax+"\"", path, comp.getMessages(), res.getMessages());
} else if (rightMax == Integer.MAX_VALUE) {
vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ:\r\n \""+leftMax+"\"\r\n vs \""+rightMax+"\"", path, comp.getMessages(), res.getMessages());
} else {
vm(IssueSeverity.INFORMATION, "Element maximum cardinalities differ:\r\n \""+leftMax+"\"\r\n 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:\r\n \""+leftMin+".."+leftMax+"\"\r\n 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:\r\n \""+leftMin+".."+leftMax+"\"\r\n 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), 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), 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;
@ -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)));
@ -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;

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

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