Merge pull request #237 from hapifhir/gg-work

override Element extension methods to also check for modifierExtensions
This commit is contained in:
Grahame Grieve 2020-06-11 21:58:20 +10:00 committed by GitHub
commit 3e55b24473
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 511 additions and 1758 deletions

View File

@ -50,6 +50,11 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
protected String abbreviation() {
return "cs";
}
@Override
protected String summary() {
return "CodeSystem: "+left.present()+" vs "+right.present();
}
}
private CodeSystem right;

View File

@ -2,9 +2,12 @@ package org.hl7.fhir.r5.comparison;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
@ -12,6 +15,7 @@ import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.model.Base;
@ -47,9 +51,27 @@ public class ComparisonRenderer implements IEvaluationContext {
public void render() throws IOException {
dumpBinaries();
for (String id : session.getCompares().keySet()) {
renderComparison(id, session.getCompares().get(id));
StringBuilder b = new StringBuilder();
for (String id : sorted(session.getCompares().keySet())) {
ResourceComparison comp = session.getCompares().get(id);
renderComparison(id, comp);
b.append("<li><a href=\""+comp.getId()+".html\">"+Utilities.escapeXml(comp.summary())+"</a></li>\r\n");
}
Map<String, Base> vars = new HashMap<>();
CodeSystemComparer cs = new CodeSystemComparer(session);
vars.put("title", new StringType(session.getTitle()));
vars.put("list", new StringType(b.toString()));
String template = templates.get("Index");
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file("index.html"));
}
private List<String> sorted(Set<String> keySet) {
List<String> list = new ArrayList<>();
list.addAll(keySet);
Collections.sort(list);
return list;
}
private void dumpBinaries() throws IOException {
@ -115,7 +137,7 @@ public class ComparisonRenderer implements IEvaluationContext {
private void renderProfile(String id, ProfileComparison comp) throws IOException {
String template = templates.get("Profile");
Map<String, Base> vars = new HashMap<>();
ProfileComparer cs = new ProfileComparer(session);
ProfileComparer cs = new ProfileComparer(session, new ProfileUtilities(session.getContext(), null, null));
vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present()));
vars.put("leftId", new StringType(comp.getLeft().getId()));
@ -124,7 +146,7 @@ public class ComparisonRenderer implements IEvaluationContext {
vars.put("rightUrl", new StringType(comp.getRight().getUrl()));
vars.put("errors", new StringType(new XhtmlComposer(true).compose(cs.renderErrors(comp))));
vars.put("metadata", new StringType(new XhtmlComposer(true).compose(cs.renderMetadata(comp, "", ""))));
// vars.put("concepts", new StringType(new XhtmlComposer(true).compose(cs.renderConcepts(comp, "", ""))));
vars.put("structure", new StringType(new XhtmlComposer(true).compose(cs.renderStructure(comp, "", "", "http://hl7.org/fhir"))));
String cnt = processTemplate(template, "CodeSystem", vars);
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", comp.getId() + "-union.json")), comp.getUnion());

View File

@ -12,6 +12,7 @@ import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
@ -27,17 +28,25 @@ public class ComparisonSession {
private String sessiondId;
private int count;
private boolean debug;
private String title;
public ComparisonSession(IWorkerContext context) {
public ComparisonSession(IWorkerContext context, String title) {
super();
this.context = context;
this.sessiondId = UUID.randomUUID().toString().toLowerCase();
this.title = title;
}
public IWorkerContext getContext() {
return context;
}
public String getTitle() {
return title;
}
public ResourceComparison compare(String left, String right) throws DefinitionException, FHIRFormatError, IOException {
CanonicalResource l = (CanonicalResource) context.fetchResource(Resource.class, left);
if (l == null) {
@ -69,7 +78,7 @@ public class ComparisonSession {
compares.put(key, csc);
return csc;
} else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
ProfileComparer cs = new ProfileComparer(this);
ProfileComparer cs = new ProfileComparer(this, new ProfileUtilities(context, null, null));
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
compares.put(key, csc);
return csc;
@ -91,9 +100,6 @@ public class ComparisonSession {
public void identify(ResourceComparison res) {
count++;
if (!Utilities.isValidId(res.getId())) {
res.setId(sessiondId+"-"+count);
}
}
public boolean isDebug() {

View File

@ -7,8 +7,11 @@ import java.util.Date;
import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.UnusedTracker;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Coding;
@ -30,6 +33,11 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class ProfileComparer extends CanonicalResourceComparer {
@ -50,10 +58,21 @@ public class ProfileComparer extends CanonicalResourceComparer {
protected String abbreviation() {
return "sd";
}
@Override
protected String summary() {
return "Profile: "+left.present()+" vs "+right.present();
}
}
public ProfileComparer(ComparisonSession session) {
private ProfileUtilities utils;
public ProfileComparer(ComparisonSession session, ProfileUtilities utils) {
super(session);
this.utils = utils;
}
@Override
@ -95,6 +114,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
DefinitionNavigator rn = new DefinitionNavigator(session.getContext(), right);
StructuralMatch<ElementDefinition> sm = new StructuralMatch<ElementDefinition>(ln.current(), rn.current());
compareElements(res, sm, ln.path(), null, ln, rn);
res.combined = sm;
}
return res;
}
@ -143,17 +163,21 @@ public class ProfileComparer extends CanonicalResourceComparer {
subset.setIsSummary(left.current().getIsSummary());
// descriptive properties from ElementDefinition - merge them:
subset.setLabel(mergeText(comp, res, path, "label", left.current().getLabel(), right.current().getLabel()));
subset.setShort(mergeText(comp, res, path, "short", left.current().getShort(), right.current().getShort()));
subset.setDefinition(mergeText(comp, res, path, "definition", left.current().getDefinition(), right.current().getDefinition()));
subset.setComment(mergeText(comp, res, path, "comments", left.current().getComment(), right.current().getComment()));
subset.setRequirements(mergeText(comp, res, path, "requirements", left.current().getRequirements(), right.current().getRequirements()));
subset.setLabel(mergeText(comp, res, path, "label", left.current().getLabel(), right.current().getLabel(), false));
subset.setShort(mergeText(comp, res, path, "short", left.current().getShort(), right.current().getShort(), false));
subset.setDefinition(mergeText(comp, res, path, "definition", left.current().getDefinition(), right.current().getDefinition(), false));
subset.setComment(mergeText(comp, res, path, "comments", left.current().getComment(), right.current().getComment(), false));
subset.setRequirements(mergeText(comp, res, path, "requirements", left.current().getRequirements(), right.current().getRequirements(), false));
subset.getCode().addAll(mergeCodings(left.current().getCode(), right.current().getCode()));
subset.getAlias().addAll(mergeStrings(left.current().getAlias(), right.current().getAlias()));
subset.getMapping().addAll(mergeMappings(left.current().getMapping(), right.current().getMapping()));
// left will win for example
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());
}
subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport());
ElementDefinition superset = subset.copy();
@ -278,7 +302,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
private DefinitionNavigator findInList(List<DefinitionNavigator> rc, DefinitionNavigator l) {
for (DefinitionNavigator t : rc) {
if (t.current().getPath().equals(l.current().getPath())) {
if (tail(t.current().getPath()).equals(tail(l.current().getPath()))) {
return t;
}
}
@ -292,8 +316,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
vm(IssueSeverity.ERROR, "Added "+name, path, comp.getMessages(), res.getMessages());
} else if (vRight == null) {
vm(IssueSeverity.ERROR, "Removed "+name, path, comp.getMessages(), res.getMessages());
} else if (Base.compareDeep(vLeft, vRight, false)) {
vm(IssueSeverity.ERROR, name+" be the same ("+toString(vLeft)+"/"+toString(vRight)+")", path, comp.getMessages(), res.getMessages());
} else if (!Base.compareDeep(vLeft, vRight, false)) {
vm(IssueSeverity.ERROR, name+" must be the same ("+toString(vLeft)+"/"+toString(vRight)+")", path, comp.getMessages(), res.getMessages());
}
}
@ -324,7 +348,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
return test;
}
private String mergeText(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String name, String left, String right) {
private String mergeText(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String name, String left, String right, boolean isError) {
if (left == null && right == null)
return null;
if (left == null)
@ -336,7 +360,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
if (left.equalsIgnoreCase(right))
return left;
if (path != null) {
vm(IssueSeverity.ERROR, "Elements differ in definition for "+name+":\r\n \""+left+"\"\r\n \""+right+"\"", path, comp.getMessages(), res.getMessages());
vm(isError ? IssueSeverity.ERROR : IssueSeverity.WARNING, "Elements differ in "+name+":\r\n \""+left+"\"\r\n \""+right+"\"", path, comp.getMessages(), res.getMessages());
}
return "left: "+left+"; right: "+right;
}
@ -661,8 +685,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
subset.setBinding(subBinding);
ElementDefinitionBindingComponent superBinding = new ElementDefinitionBindingComponent();
superset.setBinding(superBinding);
subBinding.setDescription(mergeText(comp, res, path, "description", left.getDescription(), right.getDescription()));
superBinding.setDescription(mergeText(comp, res, path, "description", left.getDescription(), right.getDescription()));
subBinding.setDescription(mergeText(comp, res, path, "description", left.getDescription(), right.getDescription(), false));
superBinding.setDescription(mergeText(comp, res, path, "description", left.getDescription(), right.getDescription(), false));
if (left.getStrength() == BindingStrength.REQUIRED || right.getStrength() == BindingStrength.REQUIRED)
subBinding.setStrength(BindingStrength.REQUIRED);
else
@ -776,7 +800,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
union.setStrength(left.getStrength());
else
union.setStrength(right.getStrength());
union.setDescription(mergeText(comp, res, path, "binding.description", left.getDescription(), right.getDescription()));
union.setDescription(mergeText(comp, res, path, "binding.description", left.getDescription(), right.getDescription(), false));
if (Base.compareDeep(left.getValueSet(), right.getValueSet(), false))
union.setValueSet(left.getValueSet());
else {
@ -802,8 +826,165 @@ public class ProfileComparer extends CanonicalResourceComparer {
return session.getContext().fetchResource(ValueSet.class, vsRef);
}
public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(Utilities.path("[tmp]", "compare"), false, true);
gen.setTranslator(session.getContext().translator());
TableModel model = gen.initComparisonTable(corePath, id);
genElementComp(null /* oome back to this later */, gen, model.getRows(), comp.combined, corePath, prefix, null, true);
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 {
Row originalRow = slicingRow;
Row typesRow = null;
List<StructuralMatch<ElementDefinition>> children = combined.getChildren();
Row row = gen.new Row();
rows.add(row);
String path = combined.either().getPath();
row.setAnchor(path);
row.setColor(utils.getRowColor(combined.either(), false));
if (eitherHasSlicing(combined))
row.setLineColor(1);
else if (eitherHasSliceName(combined))
row.setLineColor(2);
else
row.setLineColor(0);
boolean ext = false;
if (tail(path).equals("extension")) {
if (elementIsComplex(combined))
row.setIcon("icon_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX);
else
row.setIcon("icon_extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE);
ext = true;
} else if (tail(path).equals("modifierExtension")) {
if (elementIsComplex(combined))
row.setIcon("icon_modifier_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX);
else
row.setIcon("icon_modifier_extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE);
} else if (hasChoice(combined)) {
if (allAreReference(combined))
row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE);
else {
row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE);
typesRow = row;
}
} else if (combined.either().hasContentReference())
row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE);
else if (isPrimitive(combined))
row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
else if (hasTarget(combined))
row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE);
else if (isDataType(combined))
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 sName = tail(path);
String sn = getSliceName(combined);
if (sn != null)
sName = sName +":"+sn;
UnusedTracker used = new UnusedTracker();
Cell nc;
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 = utils.genElementNameCell(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
} else {
nc = utils.genElementNameCell(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
}
if (combined.hasLeft()) {
frame(utils.genElementCells(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName, nc), leftColor);
} else {
frame(spacers(row, 4, gen), leftColor);
}
if (combined.hasRight()) {
frame(utils.genElementCells(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used, ref, sName, nc), rightColor);
} else {
frame(spacers(row, 4, gen), rightColor);
}
row.getCells().add(cellForMessages(gen, combined.getMessages()));
for (StructuralMatch<ElementDefinition> child : children) {
genElementComp(defPath, gen, row.getSubRows(), child, corePath, prefix, originalRow, false);
}
}
private void frame(List<Cell> cells, String color) {
for (Cell cell : cells) {
if (color != null) {
cell.setStyle("background-color: "+color);
}
}
cells.get(0).setStyle("border-left: 1px grey solid"+(color == null ? "" : "; background-color: "+color));
cells.get(cells.size()-1).setStyle("border-right: 1px grey solid"+(color == null ? "" : "; background-color: "+color));
}
private List<Cell> spacers(Row row, int count, HierarchicalTableGenerator gen) {
List<Cell> res = new ArrayList<>();
for (int i = 0; i < count; i++) {
Cell c = gen.new Cell();
res.add(c);
row.getCells().add(c);
}
return res;
}
private String getSliceName(StructuralMatch<ElementDefinition> combined) {
// TODO Auto-generated method stub
return null;
}
private boolean isDataType(StructuralMatch<ElementDefinition> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean hasTarget(StructuralMatch<ElementDefinition> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean isPrimitive(StructuralMatch<ElementDefinition> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean allAreReference(StructuralMatch<ElementDefinition> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean hasChoice(StructuralMatch<ElementDefinition> combined) {
// TODO Auto-generated method stub
return false;
}
private boolean elementIsComplex(StructuralMatch<ElementDefinition> 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) {
// TODO Auto-generated method stub
return false;
}
private boolean eitherHasSlicing(StructuralMatch<ElementDefinition> combined) {
// TODO Auto-generated method stub
return false;
}
private String tail(String path) {
if (path.contains("."))
return path.substring(path.lastIndexOf('.')+1);
else
return path;
}
}

View File

@ -47,9 +47,7 @@ public class ResourceComparer {
return id;
}
public void setId(String id) {
this.id = abbreviation()+"-"+id;
}
protected abstract String summary();
}
public final static String COLOR_NO_ROW_LEFT = "#ffffb3";
@ -84,6 +82,7 @@ public class ResourceComparer {
XhtmlNode tbl = div.table("grid");
for (ValidationMessage vm : csc.messages) {
XhtmlNode tr = tbl.tr();
tr.style("background-color: "+colorForLevel(vm.getLevel()));
tr.td().tx(vm.getLocation());
tr.td().tx(vm.getMessage());
tr.td().tx(vm.getLevel().getDisplay());

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
public class StructuralMatch<T> {
@ -77,5 +78,14 @@ public class StructuralMatch<T> {
return messages;
}
public boolean hasErrors() {
for (ValidationMessage vm : messages) {
if (vm.getLevel() == IssueSeverity.ERROR) {
return true;
}
}
return false;
}
}

View File

@ -60,7 +60,12 @@ public class ValueSetComparer extends CanonicalResourceComparer {
@Override
protected String abbreviation() {
return "sd";
return "vs";
}
@Override
protected String summary() {
return "ValueSet: "+left.present()+" vs "+right.present();
}
}

View File

@ -286,7 +286,7 @@ public class ProfileUtilities extends TranslatingUtilities {
this.pkp = pkp;
}
private class UnusedTracker {
public static class UnusedTracker {
private boolean used;
}
@ -3219,7 +3219,7 @@ public class ProfileUtilities extends TranslatingUtilities {
return (!min.hasValue() ? "" : Integer.toString(min.getValue())) + ".." + (!max.hasValue() ? "" : max.getValue());
}
private void genCardinality(HierarchicalTableGenerator gen, ElementDefinition definition, Row row, boolean hasDef, UnusedTracker tracker, ElementDefinition fallback) {
private Cell genCardinality(HierarchicalTableGenerator gen, ElementDefinition definition, Row row, boolean hasDef, UnusedTracker tracker, ElementDefinition fallback) {
IntegerType min = !hasDef ? new IntegerType() : definition.hasMinElement() ? definition.getMinElement() : new IntegerType();
StringType max = !hasDef ? new StringType() : definition.hasMaxElement() ? definition.getMaxElement() : new StringType();
if (min.isEmpty() && definition.getUserData(DERIVATION_POINTER) != null) {
@ -3249,8 +3249,9 @@ public class ProfileUtilities extends TranslatingUtilities {
if (!min.isEmpty() || !max.isEmpty()) {
cell.addPiece(checkForNoChange(min, gen.new Piece(null, !min.hasValue() ? "" : Integer.toString(min.getValue()), null)));
cell.addPiece(checkForNoChange(min, max, gen.new Piece(null, "..", null)));
cell.addPiece(checkForNoChange(min, gen.new Piece(null, !max.hasValue() ? "" : max.getValue(), null)));
cell.addPiece(checkForNoChange(max, gen.new Piece(null, !max.hasValue() ? "" : max.getValue(), null)));
}
return cell;
}
@ -3393,13 +3394,9 @@ public class ProfileUtilities extends TranslatingUtilities {
private Row genElement(String defPath, HierarchicalTableGenerator gen, List<Row> rows, ElementDefinition element, List<ElementDefinition> all, List<StructureDefinition> profiles, boolean showMissing, String profileBaseFileName, Boolean extensions, boolean snapshot, String corePath, String imagePath, boolean root, boolean logicalModel, boolean isConstraintMode, boolean allInvariants, Row slicingRow) throws IOException, FHIRException {
Row originalRow = slicingRow;
StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1);
String s = tail(element.getPath());
if (element.hasSliceName())
s = s +":"+element.getSliceName();
Row typesRow = null;
List<ElementDefinition> children = getChildren(all, element);
boolean isExtension = (s.equals("extension") || s.equals("modifierExtension"));
// if (!snapshot && isExtension && extensions != null && extensions != isExtension)
// return;
@ -3449,71 +3446,16 @@ public class ProfileUtilities extends TranslatingUtilities {
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 + element.getId();
UnusedTracker used = new UnusedTracker();
String ref = defPath == null ? null : defPath + element.getId();
String sName = tail(element.getPath());
if (element.hasSliceName())
sName = sName +":"+element.getSliceName();
used.used = true;
if (logicalModel && element.hasRepresentation(PropertyRepresentation.XMLATTR))
s = "@"+s;
String hint = "";
hint = checkAdd(hint, (element.hasSliceName() ? translate("sd.table", "Slice")+" "+element.getSliceName() : ""));
if (hasDef && element.hasDefinition()) {
hint = checkAdd(hint, (hasDef && element.hasSliceName() ? ": " : ""));
hint = checkAdd(hint, !hasDef ? null : gt(element.getDefinitionElement()));
}
Cell left = gen.new Cell(null, ref, s, hint, null);
row.getCells().add(left);
Cell gc = gen.new Cell();
row.getCells().add(gc);
if (element != null && element.getIsModifier())
checkForNoChange(element.getIsModifierElement(), gc.addStyledText(translate("sd.table", "This element is a modifier element"), "?!", null, null, null, false));
if (element != null && element.getMustSupport())
checkForNoChange(element.getMustSupportElement(), gc.addStyledText(translate("sd.table", "This element must be supported"), "S", "white", "red", null, false));
if (element != null && element.getIsSummary())
checkForNoChange(element.getIsSummaryElement(), gc.addStyledText(translate("sd.table", "This element is included in summaries"), "\u03A3", null, null, null, false));
if (element != null && (!element.getConstraint().isEmpty() || !element.getCondition().isEmpty()))
gc.addStyledText(translate("sd.table", "This element has or is affected by some invariants ("+listConstraintsAndConditions(element)+")"), "I", null, null, null, false);
ExtensionContext extDefn = null;
if (ext) {
if (element != null && element.getType().size() == 1 && element.getType().get(0).hasProfile()) {
String eurl = element.getType().get(0).getProfile().get(0).getValue();
extDefn = locateExtension(StructureDefinition.class, eurl);
if (extDefn == null) {
genCardinality(gen, element, row, hasDef, used, null);
row.getCells().add(gen.new Cell(null, null, "?gen-e1? "+element.getType().get(0).getProfile(), null, null));
generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot);
} else {
String name = urltail(eurl);
left.getPieces().get(0).setText(name);
// left.getPieces().get(0).setReference((String) extDefn.getExtensionStructure().getTag("filename"));
left.getPieces().get(0).setHint(translate("sd.table", "Extension URL")+" = "+extDefn.getUrl());
genCardinality(gen, element, row, hasDef, used, extDefn.getElement());
ElementDefinition valueDefn = extDefn.getExtensionValueDefinition();
if (valueDefn != null && !"0".equals(valueDefn.getMax()))
genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root);
else // if it's complex, we just call it nothing
// genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile);
row.getCells().add(gen.new Cell(null, null, "("+translate("sd.table", "Complex")+")", null, null));
generateDescription(gen, row, element, extDefn.getElement(), used.used, null, extDefn.getUrl(), profile, corePath, imagePath, root, logicalModel, allInvariants, valueDefn, snapshot);
}
} else {
genCardinality(gen, element, row, hasDef, used, null);
if ("0".equals(element.getMax()))
row.getCells().add(gen.new Cell());
else
genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root);
generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot);
}
} else {
genCardinality(gen, element, row, hasDef, used, null);
if (element.hasSlicing())
row.getCells().add(gen.new Cell(null, corePath+"profiling.html#slicing", "(Slice Definition)", null, null));
else if (hasDef && !"0".equals(element.getMax()) && typesRow == null)
genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root);
else
row.getCells().add(gen.new Cell());
generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot);
}
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);
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();
@ -3545,7 +3487,7 @@ public class ProfileUtilities extends TranslatingUtilities {
hrow.setColor(getRowColor(element, isConstraintMode));
hrow.setLineColor(1);
hrow.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT);
hrow.getCells().add(gen.new Cell(null, null, s+":All Slices", "", null));
hrow.getCells().add(gen.new Cell(null, null, sName+":All Slices", "", null));
hrow.getCells().add(gen.new Cell());
hrow.getCells().add(gen.new Cell());
hrow.getCells().add(gen.new Cell());
@ -3560,7 +3502,7 @@ public class ProfileUtilities extends TranslatingUtilities {
hrow.setColor(getRowColor(element, isConstraintMode));
hrow.setLineColor(1);
hrow.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT);
hrow.getCells().add(gen.new Cell(null, null, s+":All Types", "", null));
hrow.getCells().add(gen.new Cell(null, null, sName+":All Types", "", null));
hrow.getCells().add(gen.new Cell());
hrow.getCells().add(gen.new Cell());
hrow.getCells().add(gen.new Cell());
@ -3569,7 +3511,8 @@ public class ProfileUtilities extends TranslatingUtilities {
row = hrow;
}
Row currRow = row;
Row currRow = row;
boolean isExtension = Utilities.existsInList(tail(element.getPath()), "extension", "modifierExtension");
for (ElementDefinition child : children) {
if (!child.hasSliceName())
currRow = row;
@ -3588,6 +3531,85 @@ public class ProfileUtilities extends TranslatingUtilities {
return slicingRow;
}
public Cell genElementNameCell(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) throws IOException {
String hint = "";
hint = checkAdd(hint, (element.hasSliceName() ? translate("sd.table", "Slice")+" "+element.getSliceName() : ""));
if (hasDef && element.hasDefinition()) {
hint = checkAdd(hint, (hasDef && element.hasSliceName() ? ": " : ""));
hint = checkAdd(hint, !hasDef ? null : gt(element.getDefinitionElement()));
}
Cell left = gen.new Cell(null, ref, sName, hint, null);
row.getCells().add(left);
return left;
}
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) throws IOException {
List<Cell> res = new ArrayList<>();
Cell gc = gen.new Cell();
row.getCells().add(gc);
res.add(gc);
if (element != null && element.getIsModifier())
checkForNoChange(element.getIsModifierElement(), gc.addStyledText(translate("sd.table", "This element is a modifier element"), "?!", null, null, null, false));
if (element != null && element.getMustSupport())
checkForNoChange(element.getMustSupportElement(), gc.addStyledText(translate("sd.table", "This element must be supported"), "S", "white", "red", null, false));
if (element != null && element.getIsSummary())
checkForNoChange(element.getIsSummaryElement(), gc.addStyledText(translate("sd.table", "This element is included in summaries"), "\u03A3", null, null, null, false));
if (element != null && (!element.getConstraint().isEmpty() || !element.getCondition().isEmpty()))
gc.addStyledText(translate("sd.table", "This element has or is affected by some invariants ("+listConstraintsAndConditions(element)+")"), "I", null, null, null, false);
ExtensionContext extDefn = null;
if (ext) {
if (element != null && element.getType().size() == 1 && element.getType().get(0).hasProfile()) {
String eurl = element.getType().get(0).getProfile().get(0).getValue();
extDefn = locateExtension(StructureDefinition.class, eurl);
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.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot));
} else {
String name = urltail(eurl);
nameCell.getPieces().get(0).setText(name);
// left.getPieces().get(0).setReference((String) extDefn.getExtensionStructure().getTag("filename"));
nameCell.getPieces().get(0).setHint(translate("sd.table", "Extension URL")+" = "+extDefn.getUrl());
res.add(genCardinality(gen, element, row, hasDef, used, extDefn.getElement()));
ElementDefinition valueDefn = extDefn.getExtensionValueDefinition();
if (valueDefn != null && !"0".equals(valueDefn.getMax()))
res.add(genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root));
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));
}
} else {
res.add(genCardinality(gen, element, row, hasDef, used, null));
if ("0".equals(element.getMax()))
res.add(addCell(row, gen.new Cell()));
else
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot));
}
} else {
res.add(genCardinality(gen, element, row, hasDef, used, null));
if (element.hasSlicing())
res.add(addCell(row, gen.new Cell(null, corePath+"profiling.html#slicing", "(Slice Definition)", null, null)));
else if (hasDef && !"0".equals(element.getMax()) && typesRow == null)
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root));
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));
}
return res;
}
private Cell addCell(Row row, Cell cell) {
row.getCells().add(cell);
return (cell);
}
private String checkAdd(String src, String app) {
return app == null ? src : src + app;
}
@ -3800,7 +3822,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
private String getRowColor(ElementDefinition element, boolean isConstraintMode) {
public String getRowColor(ElementDefinition element, boolean isConstraintMode) {
switch (element.getUserInt(UD_ERROR_STATUS)) {
case STATUS_HINT: return ROW_COLOR_HINT;
case STATUS_WARNING: return ROW_COLOR_WARNING;
@ -3849,7 +3871,12 @@ public class ProfileUtilities extends TranslatingUtilities {
c.getPieces().add(gen.new Piece(null, ToolingExtensions.readStringExtension(definition, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"), null));
}
}
if (root) {
if (profile.getAbstract()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br"));
c.addPiece(gen.new Piece(null, "This is an abstract profile", null));
}
}
if (definition.getPath().endsWith("url") && definition.hasFixed()) {
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "\""+buildJson(definition.getFixed())+"\"", null).addStyle("color: darkgreen")));
} else {

View File

@ -609,6 +609,10 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
public ValidationResult validateCode(ValidationOptions options, Coding code, ValueSet vs) {
assert options != null;
if (options == null) {
options = ValidationOptions.defaults();
}
CacheToken cacheToken = txCache != null ? txCache.generateValidationToken(options, code, vs) : null;
ValidationResult res = null;
if (txCache != null)

View File

@ -240,7 +240,69 @@ Modifier extensions SHALL NOT change the meaning of any elements on Resource or
}
}
public void addModifierExtension(String url, DataType value) {
if (isDisallowExtensions())
throw new Error("Extensions are not allowed in this context");
Extension ex = new Extension();
ex.setUrl(url);
ex.setValue(value);
getModifierExtension().add(ex);
}
@Override
public Extension getExtensionByUrl(String theUrl) {
org.apache.commons.lang3.Validate.notBlank(theUrl, "theUrl must not be blank or null");
ArrayList<Extension> retVal = new ArrayList<Extension>();
Extension res = super.getExtensionByUrl(theUrl);
if (res != null) {
retVal.add(res);
}
for (Extension next : getModifierExtension()) {
if (theUrl.equals(next.getUrl())) {
retVal.add(next);
}
}
if (retVal.size() == 0)
return null;
else {
org.apache.commons.lang3.Validate.isTrue(retVal.size() == 1, "Url "+theUrl+" must have only one match");
return retVal.get(0);
}
}
@Override
public void removeExtension(String theUrl) {
for (int i = getModifierExtension().size()-1; i >= 0; i--) {
if (theUrl.equals(getExtension().get(i).getUrl()))
getExtension().remove(i);
}
super.removeExtension(theUrl);
}
/**
* Returns an unmodifiable list containing all extensions on this element which
* match the given URL.
*
* @param theUrl The URL. Must not be blank or null.
* @return an unmodifiable list containing all extensions on this element which
* match the given URL
*/
@Override
public List<Extension> getExtensionsByUrl(String theUrl) {
org.apache.commons.lang3.Validate.notBlank(theUrl, "theUrl must not be blank or null");
ArrayList<Extension> retVal = new ArrayList<Extension>();
retVal.addAll(super.getExtensionsByUrl(theUrl));
for (Extension next : getModifierExtension()) {
if (theUrl.equals(next.getUrl())) {
retVal.add(next);
}
}
return java.util.Collections.unmodifiableList(retVal);
}
// end addition
}

View File

@ -319,7 +319,15 @@ public abstract class Element extends Base implements IBaseHasExtensions, IBaseE
getExtension().add(ex);
}
/**
* Returns an extension if one (and only one) matches the given URL.
*
* Note: BackbdoneElements override this to look in matching Modifier Extensions too
*
* @param theUrl The URL. Must not be blank or null.
* @return the matching extension, or null
*/
public Extension getExtensionByUrl(String theUrl) {
org.apache.commons.lang3.Validate.notBlank(theUrl, "theUrl must not be blank or null");
ArrayList<Extension> retVal = new ArrayList<Extension>();
@ -336,6 +344,13 @@ public abstract class Element extends Base implements IBaseHasExtensions, IBaseE
}
}
/**
* Remove any extensions that match (by given URL).
*
* Note: BackbdoneElements override this to remove from Modifier Extensions too
*
* @param theUrl The URL. Must not be blank or null.
*/
public void removeExtension(String theUrl) {
for (int i = getExtension().size()-1; i >= 0; i--) {
if (theUrl.equals(getExtension().get(i).getUrl()))
@ -367,9 +382,10 @@ public abstract class Element extends Base implements IBaseHasExtensions, IBaseE
* Returns an unmodifiable list containing all extensions on this element which
* match the given URL.
*
* Note: BackbdoneElements override this to add matching Modifier Extensions too
*
* @param theUrl The URL. Must not be blank or null.
* @return an unmodifiable list containing all extensions on this element which
* match the given URL
* @return an unmodifiable list containing all extensions on this element which match the given URL
*/
public List<Extension> getExtensionsByUrl(String theUrl) {
org.apache.commons.lang3.Validate.notBlank(theUrl, "theUrl must not be blank or null");
@ -382,11 +398,24 @@ public abstract class Element extends Base implements IBaseHasExtensions, IBaseE
return java.util.Collections.unmodifiableList(retVal);
}
/**
* Returns an true if this element has an extension that matchs the given URL.
*
* Note: BackbdoneElements override this to check Modifier Extensions too
*
* @param theUrl The URL. Must not be blank or null.
*/
public boolean hasExtension(String theUrl) {
return !getExtensionsByUrl(theUrl).isEmpty();
}
/**
* Returns the value as a string if this element has only one extension that matches the given URL, and that can be converted to a string.
*
* Note: BackbdoneElements override this to check Modifier Extensions too
*
* @param theUrl The URL. Must not be blank or null.
*/
public String getExtensionString(String theUrl) throws FHIRException {
List<Extension> ext = getExtensionsByUrl(theUrl);
if (ext.isEmpty())

View File

@ -201,6 +201,11 @@ public class DefinitionNavigator {
public StructureDefinition getStructure() {
return structure;
}
@Override
public String toString() {
return current().getId();
}
}

View File

@ -415,6 +415,10 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
this.span = span;
}
public Title setStyle(String value) {
super.setStyle(value);
return this;
}
}
public class Row {
@ -569,6 +573,26 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
return model;
}
public TableModel initComparisonTable(String prefix, String id) {
TableModel model = new TableModel(id, true);
model.setAlternating(true);
model.setDocoImg(prefix+"help16.png");
model.setDocoRef(prefix+"formats.html#table");
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "Name"), translate("sd.hint", "The logical name of the element"), null, 0));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Flags"), translate("sd.hint", "Information about the use of the element - Left Structure"), null, 0).setStyle("border-left: 1px grey solid"));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Card."), translate("sd.hint", "Minimum and Maximum # of times the the element can appear in the instance - Left Structure"), null, 0));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Type"), translate("sd.hint", "Reference to the type of the element - Left Structure"), null, 100));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Description & Constraints"), translate("sd.hint", "Additional information about the element - Left Structure"), null, 0).setStyle("border-right: 1px grey solid"));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "R Flags"), translate("sd.hint", "Information about the use of the element - Left Structure"), null, 0).setStyle("border-left: 1px grey solid"));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "R Card."), translate("sd.hint", "Minimum and Maximum # of times the the element can appear in the instance - Left Structure"), null, 0));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Type"), translate("sd.hint", "Reference to the type of the element - Left Structure"), null, 100));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Description & Constraints"), translate("sd.hint", "Additional information about the element - Left Structure"), null, 0).setStyle("border-right: 1px grey solid"));
model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "Comments"), translate("sd.hint", "Comments about the comparison"), null, 0));
return model;
}
public TableModel initGridTable(String prefix, String id) {
TableModel model = new TableModel(id, false);

View File

@ -14,8 +14,11 @@ import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.CodeSystemComparer;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ComparisonSession;
import org.hl7.fhir.r5.comparison.ProfileComparer;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser;
@ -24,6 +27,7 @@ import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.TextFile;
@ -103,7 +107,7 @@ public class ComparisonTests {
System.out.println("---- Set up Output ----------------------------------------------------------");
Utilities.createDirectory(Utilities.path("[tmp]", "comparison"));
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
NpmPackage npm = pcm.loadPackage("hl7.fhir.pubpack", "0.0.5");
NpmPackage npm = pcm.loadPackage("hl7.fhir.pubpack", "0.0.6");
for (String f : npm.list("other")) {
TextFile.streamToFile(npm.load("other", f), Utilities.path("[tmp]", "comparison", f));
}
@ -112,7 +116,7 @@ public class ComparisonTests {
CanonicalResource left = load("left");
CanonicalResource right = load("right");
ComparisonSession session = new ComparisonSession(context);
ComparisonSession session = new ComparisonSession(context, "Comparison Tests");
if (left instanceof CodeSystem && right instanceof CodeSystem) {
CodeSystemComparer cs = new CodeSystemComparer(session);
@ -138,11 +142,31 @@ public class ComparisonTests {
String xml3 = new XhtmlComposer(true).compose(cs.renderExpansion(csc, "", ""));
TextFile.stringToFile(HEADER + hd("Messages") + xmle + BREAK + hd("Metadata") + xml1 + BREAK + hd("Definition") + xml2 + BREAK + hd("Expansion") + xml3 + FOOTER, Utilities.path("[tmp]", "comparison", name + ".html"));
checkOutcomes(csc.getMessages(), content);
} else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
ProfileUtilities utils = new ProfileUtilities(context, null, null);
genSnapshot(utils, (StructureDefinition) left);
genSnapshot(utils, (StructureDefinition) right);
ProfileComparer pc = new ProfileComparer(session, utils);
ProfileComparison csc = pc.compare((StructureDefinition) left, (StructureDefinition) right);
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-union.json")), csc.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-intersection.json")), csc.getIntersection());
String xmle = new XhtmlComposer(true).compose(pc.renderErrors(csc));
String xml1 = new XhtmlComposer(true).compose(pc.renderMetadata(csc, "", ""));
String xml2 = new XhtmlComposer(true).compose(pc.renderStructure(csc, "", "", "http://hl7.org/fhir"));
// String xml3 = new XhtmlComposer(true).compose(cs.renderExpansion(csc, "", ""));
TextFile.stringToFile(HEADER + hd("Messages") + xmle + BREAK + hd("Metadata") + xml1 + BREAK + hd("Structure") + xml2 + FOOTER, Utilities.path("[tmp]", "comparison", name + ".html"));
checkOutcomes(csc.getMessages(), content);
} else {
throw new FHIRException("Can't compare " + left.fhirType() + " to " + right.fhirType());
}
}
private void genSnapshot(ProfileUtilities utils, StructureDefinition sd) {
StructureDefinition base = context.fetchTypeDefinition(sd.getType());
utils.generateSnapshot(base, sd, sd.getUrl(), "http://hl7.org/fhir/r4", sd.present());
}
private String hd(String text) {
return "<h2>" + text + "</h2>\r\n";
}